// 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(); }
// Node counter Deccriment // Usage: ND<CR> void parse_ND_packet(void) { if (NodeCount) { NodeCount--; } print_ack(); }
// Node counter Incriment // Usage: NI<CR> void parse_NI_packet(void) { if (NodeCount < 0xFFFFFFFEL) { NodeCount++; } print_ack(); }
// 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(); }
// 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(); }
// 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(); }
// 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(); }
//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; } }
// 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(); }
//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; }
// 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(); }
// 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(); }
// 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(); }
// 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(); }
//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; }
// 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(); }
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); } } }
// 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(); }
// 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(); }
// 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(); }