Ejemplo n.º 1
0
// Query Button
// Usage: QB<CR>
// Returns: <HasButtonBeenPushedSinceLastQB><CR> (0 or 1)
// OK<CR>
void parse_QB_packet(void)
{
	printf ((far rom char*)"%1i\r\n", ButtonPushed);
	ButtonPushed = FALSE;

	print_ack();
}
Ejemplo n.º 2
0
// Node counter Deccriment
// Usage: ND<CR>
void parse_ND_packet(void)
{
	if (NodeCount)
	{
		NodeCount--;
	}
	print_ack();
}
Ejemplo n.º 3
0
// Node counter Incriment
// Usage: NI<CR>
void parse_NI_packet(void)
{
	if (NodeCount < 0xFFFFFFFEL)
	{
		NodeCount++;
	}
	print_ack();
}
Ejemplo n.º 4
0
// Query Current
// Usage: QC<CR>
// Returns: <voltage_on_REF_RA0_net>,<voltage_on_v+_net><CR>
// Both values have a range of 0 to 1023 (10-bit ADC)
// The ADC is set up with 0V = 0 and 3.3V = 1023
// For the REF_RA0 (current adjustment pot) a value of 0V-ADC (0 counts) = 46mA
// and a value of 2.58V-ADC (800 counts) = 1.35A
// For the V+ net a value of 0V-ADC (0 counts) = 0V on V+
// and a value of 3.36V-ADC (1023 counts) = 37V on V+
// REF_RA0 comes in on AN0 (RA0)
// V+ comes in on AN11 (RC2)
void parse_QC_packet(void)
{
	unsigned int  AN0 = 0;
	unsigned int  AN11 = 0;

	// Set the channel to zero to start off with (AN0)
	ADCON0 = 0;
	// Set up right justified, 8Tad tim, Fosc/4
	ADCON1 = 0b10100100;
	
	// Clear the interrupt
	PIR1bits.ADIF = 0;

	// And make sure to always use low priority.
	IPR1bits.ADIP = 0;

	// Make sure it's on!
	ADCON0bits.ADON = 1;

	// Wait for 10ms
	QC_ms_timer = 10;
	while (QC_ms_timer);

	// And tell the A/D to GO!
	ADCON0bits.GO_DONE = 1;
	
	// Now sit and wait until the conversion is done
	while (ADCON0bits.GO_DONE)
	;

	// Now grab our result
	AN0 = ((UINT)ADRESH << 8) + ADRESL;
	
	// Set the channel to AN11
	ADCON0 = 0b00101101;
	
	// Wait for 10ms
	QC_ms_timer = 10;
	while (QC_ms_timer);

	// And tell the A/D to GO!
	ADCON0bits.GO_DONE = 1;
	
	// Now sit and wait until the conversion is done
	while (ADCON0bits.GO_DONE)
	;
	
	// Now grab our result
	AN11 = ((UINT)ADRESH << 8) + ADRESL;
	
	// Print out our results
	printf ((far rom char*)"%04i,%04i\r\n", AN0, AN11);

	print_ack();	
}	
Ejemplo n.º 5
0
// Query Current
// Usage: QC<CR>
// Returns: <voltage_on_REF_RA0_net>,<voltage_on_v+_net><CR>
// Both values have a range of 0 to 1023 (10-bit ADC)
// The ADC is set up with 0V = 0 and 3.3V = 1023
// For the REF_RA0 (current adjustment pot) a value of 0V-ADC (0 counts) = 46mA
// and a value of 2.58V-ADC (800 counts) = 1.35A
// For the V+ net a value of 0V-ADC (0 counts) = 0V on V+
// and a value of 3.36V-ADC (1023 counts) = 37V on V+
// REF_RA0 comes in on AN0 (RA0)
// V+ comes in on AN11 (RC2)
void parse_QC_packet(void)
{
    // Since access to ISR_A_FIFO[] is not protected in any way from ISR and
    // mainline code accessing at the same time, we will just wait for
    // the cycle of ADC readings to finish before we spit out our value.
    while (PIE1bits.ADIE);

	// Print out our results
	printf ((far rom char*)"%04i,%04i\r\n", ISR_A_FIFO[0], ISR_A_FIFO[11]);

	print_ack();
}	
Ejemplo n.º 6
0
// Set Node counter
// Usage: SN,<value><CR>
// <value> is a 4 byte unsigned value
void parse_SN_packet(void)
{
	unsigned long Temp;
	ExtractReturnType RetVal;
	
	RetVal = extract_number (kULONG, &Temp, kREQUIRED);
	if (kEXTRACT_OK == RetVal)
	{
		NodeCount = Temp;
	}
	print_ack();
}
Ejemplo n.º 7
0
// Set Layer
// Usage: SL,<NewLayer><CR>
void parse_SL_packet(void)
{
	// Extract each of the values.
	extract_number (kUCHAR, &Layer, kREQUIRED);

	// Bail if we got a conversion error
	if (error_byte)
	{
		return;
	}

	print_ack();
}
Ejemplo n.º 8
0
//set whether clock is displayed or not
void _displayWallClock (int disp_b)
{
    if (disp_b)
    {
        clock_display_en = 1;
    }
    else
    {
        params[0] = NULL;
        rtx_sprintf(str, SAVE_CURSOR MOVE_CURSOR EMPTY_CLOCK RESTORE_CURSOR, params);
        print_ack(str, send_env, msg_q);
        clock_display_en = 0;
    }
}
Ejemplo n.º 9
0
// Set Pen
// Usage: SP,<State>,<Duration>,<PortB_Pin><CR>
// <State> is 0 (for down) or 1 (for up)
// <Duration> is how long to wait (in milliseconds) before the next command
//      in the motion control FIFO should start.
// <PortB_Pin> Is a value from 0 to 7 and allows you to re-assign the Pen
//      RC Servo output to different PortB pins.
// This is a command that the user can send from the PC to set the pen state.
// Note that there is only one pen RC servo output - if you use the <PortB_Pin>
// parameter, then that new pin becomes the pen RC servo output. This command
// does not allow for mulitple servo signals at the same time from port B pins.
// Use the S2 command for that.
//
// This function will use the values for <serv_min>, <servo_max>,
// <servo_rate_up> and <servo_rate_down> (SC,4 SC,5, SC,11, SC,10 commands)
// when it schedules the servo command.
// 
// Internally, the parse_SP_packet() function makes a call to
// process_SP() function to actually make the change in the servo output.
//
void parse_SP_packet(void)
{
	UINT8 State = 0;
	UINT16 CommandDuration = 0;
	UINT8 Pin = DEFAULT_EBB_SERVO_PORTB_PIN;
    ExtractReturnType Ret;

	// Extract each of the values.
	extract_number (kUCHAR, &State, kREQUIRED);
	extract_number (kUINT, &CommandDuration, kOPTIONAL);
	Ret = extract_number (kUCHAR, &Pin, kOPTIONAL);

	// Bail if we got a conversion error
	if (error_byte)
	{
		return;
	}

    // Error check
	if (Pin > 7)
	{
		Pin = DEFAULT_EBB_SERVO_PORTB_PIN;
	}

    if (State > 1)
    {
        State = 1;
    }

    // Make sure that the selected pin we're going to use is an output
    // (This code only works for PortB - maybe expand it in the future for all ports.)
//    TRISB = TRISB & ~(1 << Pin);

    // Set the PRn of the Pen Servo output
    // Add 3 to get from PORTB pin number to RPn number
    if (g_servo2_RPn != (Pin + 3))
    {
        // if we are changing which pin the pen servo is on, we need to cancel
        // the servo output on the old channel first
        RCServo2_Move(0, g_servo2_RPn, 0, 0);
        // Now record the new RPn
        g_servo2_RPn = Pin + 3;
    }

    // Execute the servo state change
	process_SP(State, CommandDuration);

	print_ack();
}
Ejemplo n.º 10
0
//prints process statuses on console given the envelope message data
int CCI_printProcessStatuses (char* raw_data)
{
    if (raw_data == NULL)
    {
        return ERROR_NULL_ARG;
    }
    int * data = (int *) raw_data;
    int num_processes = *data++;
    int i;
    CHAR str[100]; 
    void * params [11];

	print_ack( "PID | STATUS                | PRIORITY\r\n" , print_env, msg_queue);
    for (i=0;i<num_processes;i++)
    {
        params[0] = &(*data++);
        params[1] = NULL;
        rtx_sprintf(str, "%4d   ", params);
        print_ack(str, print_env, msg_queue);
        switch(*data)
        {
            case P_READY:
                print_ack("ready                  ", print_env, msg_queue);
                break;
            case P_EXECUTING:
                print_ack("executing              ", print_env, msg_queue);
                break;
            case P_BLOCKED_ON_ENV_REQUEST:
                print_ack("blocked on env request ", print_env, msg_queue);
                break;
            case P_BLOCKED_ON_RECEIVE:
                print_ack("blocked on receive     ", print_env, msg_queue);
                break;
            default :
                print_ack("                       ", print_env, msg_queue);
                break;
        }
        data++;

        params[0] = &(*data++);
        params[1] = NULL;
        rtx_sprintf(str, "%2d\r\n", params);
        print_ack(str, print_env, msg_queue);
    }
    return CODE_SUCCESS;
}
Ejemplo n.º 11
0
// The Stepper Motor command
// Usage: SM,<move_duration>,<axis1_steps>,<axis2_steps>,<axis3_steps>,<axis4_steps><CR>
// <move_duration> is a number from 1 to 65535, indiciating the number of milliseconds this move should take
// <axisX_steps> is a signed 16 bit number indicating how many steps (and what direction) the axis should take
// NOTE1: <axis2_steps>, <axis3_steps> and <axis4_steps> are optional and can be left off
// If the EBB can not make the move in the speicified time, it will take as long as it needs to at max speed
// i.e. SM,1,1000 will not produce 1000steps in 1ms. Instead, it will take 40ms (25KHz max step rate)
// NOTE2: If you specify zero steps for the axies, then you effectively create a delay. Use for small
// pauses before raising or lowering the pen, for example.
void parse_SM_packet (void)
{
	unsigned int Duration;
	signed int A1Steps = 0, A2Steps = 0;

	// Extract each of the values.
	extract_number (kUINT, &Duration, kREQUIRED);
	extract_number (kINT, &A1Steps, kREQUIRED);
	extract_number (kINT, &A2Steps, kOPTIONAL);
	// Bail if we got a conversion error
	if (error_byte)
	{
		return;
	}
	process_SM(Duration, A1Steps, A2Steps);

	print_ack();
}
Ejemplo n.º 12
0
// Toggle Pen
// Usage: TP<CR>
// Returns: OK<CR>
// Just toggles state of pen arm
void parse_TP_packet(void)
{
	unsigned short CommandDuration = 500;

	// Extract each of the values.
	extract_number (kUINT, &CommandDuration, kOPTIONAL);

	// Bail if we got a conversion error
	if (error_byte)
	{
		return;
	}

	if (PenState == PEN_UP)
	{
		process_SP(PEN_DOWN, CommandDuration);
	}
	else
	{
		process_SP(PEN_UP, CommandDuration);
	}

	print_ack();
}
Ejemplo n.º 13
0
// Query Node counter
// Usage: QN<CR>
// Returns: <NodeCount><CR>
// OK<CR>
void parse_QN_packet(void)
{
	printf ((far rom char*)"%010lu\r\n", NodeCount);

	print_ack();
}
Ejemplo n.º 14
0
// Query Pen
// Usage: QP<CR>
// Returns: 0 for down, 1 for up, then OK<CR>
void parse_QP_packet(void)
{
	printf((far rom char *)"%d\n\r", PenState);

	print_ack();
}
Ejemplo n.º 15
0
//prints trace buffers on console given the envelope message data
int CCI_printTraceBuffers (char* data)
{
    if (data == NULL)
        return ERROR_NULL_ARG;
    int i;
    CHAR str[100]; 
    void * params [11];

    ipc_trace_t *send_dump = (ipc_trace_t *) data;
    ipc_trace_t *recv_dump = send_dump + IPC_MESSAGE_TRACE_HISTORY_SIZE; 
 
    print_ack("MESSAGE TRACE BUFFERS\r\n\r\n"
              " Send Trace                   || Receive Trace\r\n"
              " Dest |Sender|Message|  Time  || Dest |Sender|Message|  Time\r\n"
              " PID  |PID   |Type   |        || PID  |PID   |Type   |\r\n"
              "--------------------------------------------------------------\r\n",
              print_env, msg_queue);
    for (i=0;i<IPC_MESSAGE_TRACE_HISTORY_SIZE;i++)
    {
        if (send_dump[i].time_stamp != MAX_UINT32)
        {
            //TODO: Fix '%2u' and such in sprintf...

            params[0] = &(send_dump[i].dest_pid);
            params[1] = &(send_dump[i].send_pid);
            params[2] = &(send_dump[i].msg_type);
            params[3] = &(send_dump[i].time_stamp);
            params[4] = NULL;
            rtx_sprintf(str, "   %2u |   %2u |   %3d | %6u ||", params);
            print_ack(str,print_env,msg_queue);
        }
        else if (recv_dump[i].time_stamp != MAX_UINT32)
        {
            print_ack("      |      |       |       ||", print_env, msg_queue);
        }
        else
        {
            break;
        }
        
        if (recv_dump[i].time_stamp != MAX_UINT32)
        {
            //TODO: Fix '%2u' and such in sprintf...

            params[0] = &(recv_dump[i].dest_pid);
            params[1] = &(recv_dump[i].send_pid);
            params[2] = &(recv_dump[i].msg_type);
            params[3] = &(recv_dump[i].time_stamp);
            params[4] = NULL;
            rtx_sprintf(str, "   %2u |   %2u |   %3d | %6u\r\n", params);
            print_ack (str, print_env, msg_queue);
        }
        else
        {
            print_ack("      |      |       |       \r\n", print_env, msg_queue);
        }
    }        
    
    print_ack("\r\n", print_env, msg_queue);

    return CODE_SUCCESS;
}
Ejemplo n.º 16
0
// Stepper (mode) Configure command
// SC,1,0<CR> will use just solenoid output for pen up/down
// SC,1,1<CR> will use servo on RB1 for pen up/down
// SC,1,2<CR> will use servo on RB1 for pen up/down, but with ECCP2 (PWM) in hardware (default)
// SC,2,0<CR> will use built-in stepper driver chips (default)
// SC,2,1<CR> will use the following pins for stepper driver outputs (EBB_V11)
//		ENABLE1 = RA5
//		ENABLE2 = RB5
//		STEP1 = RD1
//		DIR1 = RD0
//		STEP2 = RC2
//		DIR2 = RC0
// SC,4,<servo2_min><CR> will set <servo2_min> as the minimum value for the servo (1 to 65535)
// SC,5,<servo2_max><CR> will set <servo2_max> as the maximum value for the servo (1 to 65535)
// SC,6,<servo_min><CR> will set <servo_min> as the minimum value for the servo (1 to 11890)
// SC,7,<servo_max><CR> will set <servo_max> as the maximum value for the servo (1 to 11890)
// SC,8,<servo2_slots><CR> sets the number of slots for the servo2 system (1 to 24)
// SC,9,<servo2_slotMS><CR> sets the number of ms in duration for each slot (1 to 6)
// SC,10,<servo2_rate><CR> sets the rate of change for the servo (both up and down)
// SC,11,<servo2_rate><CR> sets the pen up speed
// SC,12,<servo2_rate><CR> sets the pen down speed
// SC,13,1<CR> enables RB3 as parallel input to PRG button for pause detection
// SC,13,0<CR> disables RB3 as parallel input to PRG button for pause detection
// SC,14,1<CR> enables solenoid output on RB4
// SC,14,0<CR> disables solenoid output on RB4
void parse_SC_packet (void)
{
	unsigned char Para1 = 0;
	unsigned int Para2 = 0;

	// Extract each of the values.
	extract_number (kUCHAR, &Para1, kREQUIRED);
	extract_number (kUINT, &Para2, kREQUIRED);

	// Bail if we got a conversion error
	if (error_byte)
	{
		return;
	}

	// Check for command to select which (solenoid/servo) gets used for pen
	if (Para1 == 1)
	{
        // Use just solenoid
		if (Para2 == 0)
		{
            gUseSolenoid = TRUE;
            gUseRCPenServo = FALSE;
            // Turn off RC signal on Pen Servo output
            RCServo2_Move(0, g_servo2_RPn, 0, 0);
        }
        // Use just RC servo
		else if (Para2 == 1)
		{
            gUseSolenoid = FALSE;
            gUseRCPenServo = TRUE;
		}
        // Use solenoid AND servo (default)
		else
		{
            gUseSolenoid = TRUE;
            gUseRCPenServo = TRUE;
		}
        // Send a new command to set the state of the servo/solenoid
		process_SP(PenState, 0);
	}
	// Check for command to switch between built-in drivers and external drivers
	else if (Para1 == 2)
	{
		if (Para2 == 0)
		{
			UseBuiltInDrivers = TRUE;
			// Initalize the alternate driver I/O ports
			Dir1AltIO_TRIS = 0;
			Dir2AltIO_TRIS = 0;
			Step1AltIO_TRIS = 0;
			Step2AltIO_TRIS = 0;
			Enable1AltIO_TRIS = 0;
			Enable2AltIO_TRIS = 0;
		}
		else
		{
			UseBuiltInDrivers = FALSE;
		}
	}
	// Set <min_servo> for Servo2 method
	else if (Para1 == 4)
	{
		g_servo2_min = Para2;
	}
	// Set <max_servo> for Servo2
	else if (Para1 == 5)
	{
		g_servo2_max = Para2;
	}
	// Set <gRC2Slots>
	else if (Para1 == 8)
	{
		if (Para2 > MAX_RC2_SERVOS)
		{
			Para2 = MAX_RC2_SERVOS;
		}
		gRC2Slots = Para2;
	}
	else if (Para1 == 9)
	{
		if (Para2 > 6)
		{
			Para2 = 6;
		}
		gRC2SlotMS = Para2;
	}
	else if (Para1 == 10)
	{
		g_servo2_rate_up = Para2;
		g_servo2_rate_down = Para2;
	}
	else if (Para1 == 11)
	{
		g_servo2_rate_up = Para2;
	}
	else if (Para1 == 12)
	{
		g_servo2_rate_down = Para2;
	}
	if (Para1 == 13)
	{
		if (Para2)
		{
			UseAltPause = TRUE;
		}
		else
		{
			UseAltPause = FALSE;
		}			
	}
	print_ack();
}
Ejemplo n.º 17
0
void start_wallclock()
{
    uint32_t status;
    //initialise
    offset = 0; 
    ref = 0;
    clock_display_en = 0; //clock not displayed by default
    timeout_env = request_msg_env();
    send_env = request_msg_env();
    msg_q = msg_env_queue_create(); 

    status = request_delay ( ONE_SECOND_DELAY, WAKEUP_CODE, timeout_env); 
    if (status != CODE_SUCCESS)
    {
        params[0] = &status;
        params[1] = NULL;
        rtx_sprintf(str, "request_delay failed with status %d\r\n", params);
        print_ack(str, send_env, msg_q);
    }
    
    MsgEnv* env;

    while (1)
    {
        if (msg_env_queue_is_empty(msg_q))
        {
            env = receive_message();
        }
        else
        {
            env = msg_env_queue_dequeue(msg_q);
        }

        //envelope from timing services
        if (env->msg_type == WAKEUP_CODE)
        {
            status = request_delay( ONE_SECOND_DELAY, WAKEUP_CODE, timeout_env);
            if (status != CODE_SUCCESS)
            {
                params[0] = &status;
                params[1] = NULL;
                rtx_sprintf(str, "request_delay failed with status %d\r\n", params);
                print_ack(str, send_env, msg_q);
            }
            //86400 = 24hrs in secs
            int32_t clock_time = (int32_t)((get_system_time()-ref)/100
                                 +offset)%SEC_IN_HR;
            if (clock_display_en)
            {
                int32_t hr, min, sec;
                hr = clock_time/3600;
                min = (clock_time%3600)/60;
                sec = clock_time%60;

                params[0] = &hr;
                params[1] = &min;
                params[2] = &sec;
                params[3] = NULL;
                rtx_sprintf(str, SAVE_CURSOR MOVE_CURSOR CLOCK_FORMAT
                            RESTORE_CURSOR, params);
                print_ack(str, send_env, msg_q);
            }
        }
        else if (env->msg_type == CLOCK_ON)
        {
            _displayWallClock (1);
            env->msg_type = CLOCK_RET;
            send_message(env->send_pid,env);
        }
        else if (env->msg_type == CLOCK_OFF)
        {
            _displayWallClock (0);
            env->msg_type = CLOCK_RET;
            send_message(env->send_pid,env);
        }
        else if (env->msg_type == CLOCK_SET) 
        {
            int status = _setWallClock (env->msg);
            if (status == ERROR_ILLEGAL_ARG)
            {
                params[0] = NULL;
                rtx_sprintf( str, "c\r\n"
                           "Sets the console clock (24h).\r\n"
                           "Usage: c <hh:mm:ss>\r\n"
                           "hh must be 00-23\r\n"
                           "mm must be 00-59\r\n"
                           "ss must be 00-59\r\n", params );
                print_ack(str, send_env, msg_q);
            }
            else if (status != CODE_SUCCESS)
            {
                params[0] = &status;
                params[1] = NULL;
                rtx_sprintf( str, "CCI_setClock failed with status %d\r\n", params);
                print_ack(str, send_env, msg_q);
            }
            env->msg_type = CLOCK_RET;
            send_message(env->send_pid,env);
        }
    }
}
Ejemplo n.º 18
0
// Query Layer
// Usage: QL<CR>
// Returns: <Layer><CR>
// OK<CR>
void parse_QL_packet(void)
{
	printf ((far rom char*)"%03i\r\n", Layer);

	print_ack();
}
Ejemplo n.º 19
0
// Enable Motor
// Usage: EM,<EnableAxis1>,<EnableAxis2>,<EnableAxis3>,<EnableAxis4><CR>
// Everything afer EnableAxis1 is optional
// Each parameter can have a value of
//		0 to disable that motor driver
// FOR OLD DRIVER CHIP
//		1 to enable the driver in 1/8th step mode
//		2 to enable the driver in 1/4 step mode
//		3 to enable the driver in 1/2 step mode
//		4 to enable the driver in full step mode
// FOR NEW DRIVER CHIP (only first parameter applies, and it applies to both drivers)
//		1 to enable the driver in 1/16th step mode
//		2 to enable the driver in 1/8 step mode
//		3 to enable the driver in 1/4 step mode
//		4 to enable the driver in 1/2 step mode
//		5 to enable the driver in full step mode
// If you disable a motor, it goes 'limp' (we clear the ENABLE pin on that motor's
// driver chip)
void parse_EM_packet(void)
{
	unsigned char EA1, EA2, EA3, EA4;
	ExtractReturnType RetVal;

	// Extract each of the values.
	RetVal = extract_number (kUCHAR, &EA1, kREQUIRED);
	if (kEXTRACT_OK == RetVal)
	{
		// Bail if we got a conversion error
		if (error_byte)
		{
			return;
		}
		if (UseBuiltInDrivers)
		{
			if (EA1 > 0)
			{
				Enable1IO = ENABLE_MOTOR;
				if (EA1 == 1)
				{
					MS1_IO = 1;
					MS2_IO = 1;
					MS3_IO = 1;
				}
				if (EA1 == 2)
				{
					MS1_IO = 1;
					MS2_IO = 1;
					MS3_IO = 0;
				}
				if (EA1 == 3)
				{
					MS1_IO = 0;
					MS2_IO = 1;
					MS3_IO = 0;
				}
				if (EA1 == 4)
				{
					MS1_IO = 1;
					MS2_IO = 0;
					MS3_IO = 0;
				}				
				if (EA1 == 5)
				{
					MS1_IO = 0;
					MS2_IO = 0;
					MS3_IO = 0;
				}				
			}
			else
			{
				Enable1IO = DISABLE_MOTOR;
			}
		}
		else
		{
			if (EA1 > 0)
			{
				Enable1AltIO = ENABLE_MOTOR;
			}
			else
			{
				Enable1AltIO = DISABLE_MOTOR;
			}
		}
	}

	RetVal = extract_number (kUCHAR, &EA2, kOPTIONAL);
	if (kEXTRACT_OK == RetVal)
	{
		// Bail if we got a conversion error
		if (error_byte)
		{
			return;
		}
		if (UseBuiltInDrivers)
		{
			if (EA2 > 0)
			{
				Enable2IO = ENABLE_MOTOR;
			}
			else
			{
				Enable2IO = DISABLE_MOTOR;
			}
		}
		else
		{
			if (EA2 > 0)
			{
				Enable2AltIO = ENABLE_MOTOR;
			}
			else
			{
				Enable2AltIO = DISABLE_MOTOR;
			}
		}
	}
	print_ack();
}
Ejemplo n.º 20
0
// Enable Motor
// Usage: EM,<EnableAxis1>,<EnableAxis2><CR>
// Everything afer EnableAxis1 is optional
// Each parameter can have a value of
//		0 to disable that motor driver
// FOR OLD DRIVER CHIP (A3967) - can do separate enables for each axis
//		1 to enable the driver in 1/8th step mode
//		2 to enable the driver in 1/4 step mode
//		3 to enable the driver in 1/2 step mode
//		4 to enable the driver in full step mode
// FOR NEW DRIVER CHIP (A4988/A4983)
// (only first parameter applies, and it applies to both drivers)
//		1 to enable the driver in 1/16th step mode
//		2 to enable the driver in 1/8 step mode
//		3 to enable the driver in 1/4 step mode
//		4 to enable the driver in 1/2 step mode
//		5 to enable the driver in full step mode
// If you disable a motor, it goes 'limp' (we clear the ENABLE pin on that motor's
// driver chip)
// Note that when using 0 or 1 for a paraemter, you can use both axis even
// on a 'new' driver chip board. (i.e. EM,0,1 will disable motor 1 and enable 2)
// Note that the MSx lines do not come to any headers, so even when an external
// source is controlling the drivers, the PIC still needs to control the
// MSx lines.
void parse_EM_packet(void)
{
	unsigned char EA1, EA2;
	ExtractReturnType RetVal;

	// Extract each of the values.
	RetVal = extract_number (kUCHAR, &EA1, kREQUIRED);
	if (kEXTRACT_OK == RetVal)
	{
		// Bail if we got a conversion error
		if (error_byte)
		{
			return;
		}
		if (
            (DriverConfiguration == PIC_CONTROLS_DRIVERS)
            ||
            (DriverConfiguration == EXTERNAL_CONTROLS_DRIVERS)
        )
		{
			if (EA1 > 0)
			{
				if (DriverConfiguration == PIC_CONTROLS_DRIVERS)
                {
                    Enable1IO = ENABLE_MOTOR;
                }
				if (EA1 == 1)
				{
					MS1_IO = 1;
					MS2_IO = 1;
					MS3_IO = 1;
				}
				if (EA1 == 2)
				{
					MS1_IO = 1;
					MS2_IO = 1;
					MS3_IO = 0;
				}
				if (EA1 == 3)
				{
					MS1_IO = 0;
					MS2_IO = 1;
					MS3_IO = 0;
				}
				if (EA1 == 4)
				{
					MS1_IO = 1;
					MS2_IO = 0;
					MS3_IO = 0;
				}				
				if (EA1 == 5)
				{
					MS1_IO = 0;
					MS2_IO = 0;
					MS3_IO = 0;
				}				
			}
			else
			{
				if (DriverConfiguration == PIC_CONTROLS_DRIVERS)
                {
    				Enable1IO = DISABLE_MOTOR;
                }
			}
		}
        else if (DriverConfiguration == PIC_CONTROLS_EXTERNAL)
		{
			if (EA1 > 0)
			{
				Enable1AltIO = ENABLE_MOTOR;
			}
			else
			{
				Enable1AltIO = DISABLE_MOTOR;
			}
		}
	}

	RetVal = extract_number (kUCHAR, &EA2, kOPTIONAL);
	if (kEXTRACT_OK == RetVal)
	{
		// Bail if we got a conversion error
		if (error_byte)
		{
			return;
		}
		if (DriverConfiguration == PIC_CONTROLS_DRIVERS)
		{
			if (EA2 > 0)
			{
				Enable2IO = ENABLE_MOTOR;
			}
			else
			{
				Enable2IO = DISABLE_MOTOR;
			}
		}
        else if (DriverConfiguration == PIC_CONTROLS_EXTERNAL)
		{
			if (EA2 > 0)
			{
				Enable2AltIO = ENABLE_MOTOR;
			}
			else
			{
				Enable2AltIO = DISABLE_MOTOR;
			}
		}
	}

    print_ack();
}