void vt100_resetParms() { vt100_set_errorCode(0); // init to zero at run-time vt100_clear_errorText(); // set the "Reset/Power-Up Conditions" from the ATC 5.2b spec, page 7-4 vt100_set_autoRepeat( 0 ); vt100_set_autoWrap( 0 ); vt100_set_autoScroll( 0 ); vt100_set_currentAttribs( NO_ATTRIBUTES ); // clear Reverse Video, Character Blink and Underline Attribs, + Special Char vt100_set_cursorBlink( 1 ); // Turn on Cursor and its blinking state vt100_set_cursorState( 1 ); vt100_set_cursorPos( 1, 1); // cursor at top left vt100_clear_specialChars(); // clear all down to 0 bits which should be a blank char // set the initial tab stops at 9, 17, 25, 33 per ATC 5.2b spec, page 7-4 vt100_set_tabStop( (int16_t) ( 9 - 1) ); // our array starts with 0 vt100_set_tabStop( (int16_t) (17 - 1) ); vt100_set_tabStop( (int16_t) (25 - 1) ); vt100_set_tabStop( (int16_t) (33 - 1) ); vt100_set_backLightTimeout( (int16_t) 6 ); // set timeout to 60 secs vt100_set_backLight( (int16_t) 0); // turn off the backlight return; } // end - vt100_resetParms()
void process_ESC_Seq(int16_t fd, VIRTUAL_DISPLAY *VD_ptr, char **pBuffPtr) { char ESC_sequence[MAX_ESC_SEQ_LEN]; // holds the <ESC> sequence chars char outputSeqBuffer[MAX_ESC_SEQ_LEN]; // output buffer to make string for serial port write int16_t outBufLen = 0; // length of the output string int16_t numBytesWritten = 0; // bytes written to the Serial Port char nextChar = 0; int tempIntValue = 0; int16_t seqCode = 0; int seqValue = 0; int16_t initCol = 0; // starting column (from cursorPos) in a line int16_t i=0, j=0; static int ESC_line = 0, ESC_col = 0; // for Py;Px conversions char *pESC = ESC_sequence; // ptr for parsing through ESC sequence char **pTextArray = VD_ptr->pText; // set up the malloc'd data area pointers char **pAttribsArray = VD_ptr->pAttribs; char *pRowText = NULL; char *pRowAttribs = NULL; //static int seq = 0; ESC_sequence[0] = ESC_CHAR; // init the start of the sequence ESC_sequence[1] = 0; ESC_sequence[2] = 0; ESC_sequence[3] = 0; pRowText = pTextArray[cursorPos.cp_row]; pRowAttribs = pAttribsArray[cursorPos.cp_row]; //read the ESC sequence nextChar = getNextChar(fd, pBuffPtr); switch (nextChar) { case 'D': // scroll window up one line vt100_scrollVD( 1 ); break; case 'E': // move to next line ? start of line or just next row below? // if ( (cursorPos.cp_row += 1) > numRows - 1 ) if( cursorPos.cp_row < (numRows - 1) ) cursorPos.cp_row++ ; // rows start with 0 // cursorPos.cp_col = 0; // comment out for now - just move down 1 row break; case 'H': // set tab at current column tabCol = cursorPos.cp_col; tabStops[tabCol] = 'T'; // show an ASCII 'T' instead of ' ' seqCode = 0; break; case 'M': // scroll window down one line vt100_scrollVD( -1 ); break; case 'P': // Compose Special Character // sequence is <ESC> P P1 [ Pn ; Pn ; Pn ; .... f ESC_sequence[1] = 'P'; seqCode = get_ESC_Seq(fd, ESC_sequence, pBuffPtr); if( seqCode == CURSOR_POSITION ) // should have found an 'f' terminator seqCode = COMPOSE_SPECIAL; // this should occur #if DEBUG_ON & DEBUG_SPECIAL else printf("\n process_ESC_seq(): Compose SPECIAL CHAR # %d: seqCode was %d, should be %d ", ESC_sequence[2], seqCode, CURSOR_POSITION ); #endif break; case '[': // <ESC> [ sequence // get rest of sequence and process ESC_sequence[1] = '['; seqCode = get_ESC_Seq(fd, ESC_sequence, pBuffPtr); //printf("get_ESC_Seq:ESC[0x%02x,0x%02x seqCode=%d\n", ESC_sequence[2], ESC_sequence[3], seqCode); break; case '6': // <ESC> 6 n sequence - CURSOR_POSITION request // this is an older VT-100 original query // CursorPos, Parameters/Attributes, auxSwitch status if( (nextChar = getNextChar(fd, pBuffPtr)) == 'n' ) { // dummy this in to be the same as the new STATUS QUERY COMMANDS for RESPONSES ESC_sequence[1] = '['; ESC_sequence[2] = '6'; ESC_sequence[3] = 'n'; seqCode = STATUS_QUERY; } else { ESC_sequence[1] = '6'; ESC_sequence[2] = nextChar; // don't know really what to do here - this is not defined // no further processing will happen without the 'seqCode' being set } break; case '7': // <ESC> 7 sequence - SAVE_CURSOR_POS ESC_sequence[1] = '7'; seqCode = SAVE_CURSOR_POS; break; case '8': // <ESC> 8 sequence - REST_CURSOR_POS ESC_sequence[1] = '8'; seqCode = REST_CURSOR_POS; break; case 'G': // <ESC> G sequence - Graphics Mode Commands ESC_sequence[1] = 'G'; nextChar = getNextChar(fd, pBuffPtr); ESC_sequence[2] = nextChar; switch (nextChar) { case 'U': nextChar = getNextChar(fd, pBuffPtr); if (nextChar == '0') graphicModeFlags &= ~(GRAPHIC_UNDERLAY_1 | GRAPHIC_UNDERLAY_2); else if (nextChar == '1') graphicModeFlags |= GRAPHIC_UNDERLAY_1; else if (nextChar == '2') graphicModeFlags |= GRAPHIC_UNDERLAY_2; ESC_sequence[3] = nextChar; break; case 'O': nextChar = getNextChar(fd, pBuffPtr); if (nextChar == '0') graphicModeFlags &= ~(GRAPHIC_OVERLAY_1 | GRAPHIC_OVERLAY_2); else if (nextChar == '1') graphicModeFlags |= GRAPHIC_OVERLAY_1; else if (nextChar == '2') graphicModeFlags |= GRAPHIC_OVERLAY_2; ESC_sequence[3] = nextChar; break; case 'C': nextChar = getNextChar(fd, pBuffPtr); if (nextChar == '0') graphicModeFlags &= ~(GRAPHIC_CURSOR_U | GRAPHIC_CURSOR_O); else if (nextChar == 'U') graphicModeFlags |= GRAPHIC_CURSOR_U; else if (nextChar == 'O') graphicModeFlags |= GRAPHIC_CURSOR_O; ESC_sequence[3] = nextChar; break; default: break; } break; default: // unknown or not-handled ESC sequence break; } if( seqCode > 0 ) // valid ESC Sequence that needs processing? { seqValue = 0; if( isdigit ( ESC_sequence[2])) { if( sscanf( &ESC_sequence[2], "%d", &seqValue) != 1 ) { printf("sscanf error for seqCode %d\n", seqCode); seqValue = 0; } } else if( isdigit ( ESC_sequence[3])) // is this <ESC>[?NN or something similar { if( sscanf( &ESC_sequence[3], "%d", &seqValue) != 1 ) { printf("sscanf error for seqCode %d\n", seqCode); seqValue = 0; } } // now have valid sequence code and numeric value if present #if DEBUG_ON & DEBUG_ESC_SEQ printf("process_ESC_sequence for <ESC> [ 0x%02x, seqCode=%d\n", seqValue, seqCode); #endif switch( seqCode) { case CURSOR_UP: if ( (cursorPos.cp_row -= seqValue) < 0 ) cursorPos.cp_row = 0; break; case CURSOR_DOWN: if ( (cursorPos.cp_row += seqValue) >= (numRows - 1) ) // cursorPos values start with 0 cursorPos.cp_row = numRows - 1; // rows start with 0 break; case CURSOR_RIGHT: if ( (cursorPos.cp_col += seqValue) >= (numCols - 1) ) // cursorPos values start with 0 cursorPos.cp_col = numCols - 1; // force to last position break; case CURSOR_LEFT: if ( (cursorPos.cp_col -= seqValue) < 0 ) cursorPos.cp_col = 0; // force to start of line position break; case HOME_CURSOR: cursorPos.cp_row = 0; cursorPos.cp_col = 0; break; case CURSOR_POSITION: cursorPos.cp_row = 0; cursorPos.cp_col = 0; // check for row;column position as opposed to top left if( isdigit( ESC_sequence[2]) ) // if no number - then home to top left { if( sscanf(&ESC_sequence[2], "%d;%d", &ESC_line, &ESC_col) >= 2 ) { // ESC sequence starts row and cols with a 1 to 8 row # and 1 to 40 col # // first - confirm within boundaries and set to boundaries if be if( ESC_line < 1 ) ESC_line = 1; if( ESC_col < 1 ) ESC_col = 1; if( ESC_line > numRows) ESC_line = numRows; if( ESC_col > numCols) ESC_col = numCols; // internally we use cols from 0 to numCols and // row numbers from 0 to numRows // so we will subtract 1 from ESC_line & ESC_col cursorPos.cp_row = ESC_line - 1; cursorPos.cp_col = ESC_col - 1; } } break; case SET_AUTO_MODES: //printf("\nprocess_ESC_Seq() - [?%d h - SET_AUTO_MODES\n", seqValue); switch (seqValue) { case 5: if( ESC_sequence[2] == '?') // set Reverse Video vt100_set_reverseVideo((int16_t) ON ); else if( ESC_sequence[2] == '<') vt100_set_backLight( (int16_t) ON ); else #if DEBUG_ON printf("\n process_ESC_Seq() - [ ??? 5 h - SET_AUTO_MODES "); #else ; // do nothing - maybe non-implemented <ESC> sequence #endif break; case 7: vt100_set_autoWrap((int16_t) TEXT_WRAP_NL); break; case 8: vt100_set_autoRepeat( (int16_t) ON ); break; case 24: // UNDERLINE MODE ON currentAttribs |= ATTRIB_UNDER; // bit flags "OR" break; case 25: // could be 25 or 025 in <ESC>[ sequence - 2 different actions if(ESC_sequence[2] == '0') vt100_set_cursorState(ON); else currentAttribs |= ATTRIB_BLINK; // bit flags "OR" break; case 27: // set Reverse Video vt100_set_reverseVideo((int16_t) ON ); currentAttribs |= ATTRIB_REVERSE; break; case 33: // Cursor Blink ON vt100_set_cursorBlink(ON); break; case 47: // AutoScroll ON vt100_set_autoScroll( (int16_t) ON ); break; default: break; } break; case CLEAR_AUTO_MODES: switch (seqValue) { case 5: if( ESC_sequence[2] == '?') // turn off Reverse Video vt100_set_reverseVideo((int16_t) OFF ); else if( ESC_sequence[2] == '<') vt100_set_backLight( (int16_t) OFF ); else #if DEBUG_ON printf("\n process_ESC_Seq() - [ ??? 5 l - CLEAR_AUTO_MODES "); #else ; // do nothing - maybe non-implemented <ESC> sequence #endif break; case 7: vt100_set_autoWrap((int16_t) TEXT_WRAP_OFF); break; case 8: vt100_set_autoRepeat( (int16_t) OFF ); break; case 24: // UNDERLINE MODE OFF currentAttribs &= ~ATTRIB_UNDER; break; case 25: // could be 25 or 025 in <ESC>[ sequence - 2 different actions if(ESC_sequence[2] == '0') vt100_set_cursorState(OFF); else currentAttribs &= ~ATTRIB_BLINK; // clear the Blink bit break; case 27: // Turn Off Reverse Video vt100_set_reverseVideo((int16_t) OFF ); currentAttribs &= ~ATTRIB_REVERSE; break; case 33: // Cursor Blink OFF vt100_set_cursorBlink(OFF); break; case 47: // AutoScroll OFF vt100_set_autoScroll( (int16_t) OFF ); break; default: break; } break; case CLEAR_DISPLAY: // have to do the rest of the codes - clear is only switch (seqValue) { case 0: // Clear screen from cursor down i = cursorPos.cp_row; initCol = cursorPos.cp_col; for(i = cursorPos.cp_row; i < numRows ; i++ ){ pRowText = pTextArray[i]; pRowAttribs = pAttribsArray[i]; for(j = initCol; j < numCols; j++ ) { *pRowText++ = ' '; // set to blanks for Text and *pRowAttribs++ = '0'; // ASCII Zeroes for the attributes // VD_ptr->text[i][j] = ' '; // blanks for cleared text // VD_ptr->attribs[i][j] = '0'; // zero for cleared attributes } initCol = 0; // clear all the rest of the rows going down } break; case 1: // Clear screen from cursor up i = cursorPos.cp_row; initCol = cursorPos.cp_col; for(i = cursorPos.cp_row; i >= 0 ; i-- ){ pRowText = pTextArray[i]; pRowAttribs = pAttribsArray[i]; for(j = initCol; j >= 0; j-- ) { *pRowText++ = ' '; // set to blanks for Text and *pRowAttribs++ = '0'; // ASCII Zeroes for the attributes // VD_ptr->text[i][j] = ' '; // blanks for cleared text // VD_ptr->attribs[i][j] = '0'; // zero for cleared attributes } initCol = numCols - 1; // clear rest of rows going up, starting from last column } break; case 2: // Clear entire screen vt100_clearVD(); break; default: break; } break; case CLEAR_LINE: // cursorPos has line number switch (seqValue) { case 0: // Clear from cursor to the right for(j = cursorPos.cp_col; j < numCols; j++ ) { pRowText[j] = ' '; // blanks for cleared text pRowAttribs[j] = '0'; // zero for cleared attributes } break; case 1: // Clear line from cursor to the left for(j = cursorPos.cp_col; j >= 0; j-- ) { pRowText[j] = ' '; // blanks for cleared text pRowAttribs[j] = '0'; // zero for cleared attributes } break; case 2: // Clear entire line for(j = 0; j < numCols; j++ ) { pRowText[j] = ' '; // blanks for cleared text pRowAttribs[j] = '0'; // zero for cleared attributes } break; default: break; } break; case CLEAR_TABS: switch (seqValue) { case 0: // Clear a tab at the current column tabStops[cursorPos.cp_col] = '0'; break; case 3: // Clear all tab stops for(j = 0; j < numCols; j++ ) { tabStops[j] = '0'; } break; default: // unknown tabstop seqValue break; } break; case CHAR_ATTRIBUTES: switch (seqValue) { case RESET_ATTRIBUTES: // clear all attributes // what about the bit 8 for the Special Character??? // it can't be kept in currentAttribs because it only applies to one character at a time currentAttribs = '0'; break; case BLINK_ON: currentAttribs |= ATTRIB_BLINK; // bit flags "OR" break; case REVERSE_ON: currentAttribs |= ATTRIB_REVERSE; // bit flags "OR" break; case UNDER_ON: currentAttribs |= ATTRIB_UNDER; // bit flags "OR" break; default: break; } break; case BACKLIGHT_TIMEOUT: vt100_set_backLightTimeout(seqValue); // sequence value sets timeout in seconds // NOTE: These routines currently have no implementation of // this timeout countdown between key strokes by user // at the Front Panel. break; case COMPOSE_SPECIAL: // Compose a Special bit-mapped character - seqValue has which one // sequence is <ESC> P P1 [ Pn ; Pn ; Pn ; .... f pESC = &ESC_sequence[4]; // should be the first 8-bit # seqValue = ESC_sequence[2] - '0'; if ((seqValue < 1) || (seqValue > 8)) { printf("\nvt100_processInput error: invalid special char %d", seqValue); break; } #if DEBUG_ON & DEBUG_SPECIAL printf("\n Composing SpecChar # %d [%c] : %s ", seqValue, ESC_sequence[2], &ESC_sequence[1] ); #endif for(i=0; i < BYTES_PER_SPEC_CHAR; i++) // up to 8 elements before the 'f' delimiter { sscanf(pESC, "%d", &tempIntValue); specialChars[seqValue-1][i] = (uint8_t) tempIntValue; while( isdigit( *pESC) ) // bypass the number just converted pESC++; if( *pESC == ';' ) { pESC++; // skip the ';' delimiter to get to the next bit-map byte } if( *pESC == 'f' ){ // this will allow a ";f" sequence even though it might be wrong i++; // account for this Pn Value before breaking the loop break; // special chars can be 5 - 8 columns long; Pn = P1 - P8 } } #if DEBUG_ON & DEBUG_SPECIAL if( *pESC != 'f' ) { printf("\n vt100_processInput error: loading Special Char # %d: terminator '%c' should be 'f'", seqValue, *pESC); // NOTE: This could be caused it there are more than 8 Pn values, which would make a very wide // Special Character, which would be invalid and cleared out } #endif if( (i >= MIN_SPEC_CHAR_COLS ) && (i <= MAX_SPEC_CHAR_COLS ) ) { specialCharColumns[seqValue-1] = i; // should be a number in range 5 - 8 } else { // should clear out this invalid attempt #if DEBUG_ON & DEBUG_SPECIAL printf("\n vt100_processInput: Invalid attempt to set up Special Character # %d - only %d columns", seqValue, i); #endif for(i=0; i < BYTES_PER_SPEC_CHAR; i++) // up to 8 elements before the 'f' delimiter { specialChars[seqValue-1][i] = 0; } } break; case SPECIAL_CHAR: // display one of 8 Special Characters as a ASCII Digit '1' thru '8' // and put the Atrribute Bit On for Speciall Char for that character only // The special character number is in the "seqValue" variable processInputChar((char) ((uint8_t) ( (0x30 + seqValue) | 0x80) ), pVD); // ASCII '0' + seq + bit 7 break; case STATUS_QUERY: // one of three possible queries - cursorPos, attribs/parameters, auxSwitch state // all need to have responses generated and written to the serial port fd if open // have to send (transmit) cursor pos message onto Serial Port (fd) // sequence is: <ESC>[<row>;<col>R or similar // clear and load an output buffer for response #if DEBUG_ON & DEBUG_SERIAL printf("\n vt100_process_ESC_Seq: STATUS QUERY # %c\n", ESC_sequence[2]); #endif for(i = 0; i < MAX_ESC_SEQ_LEN; i++ ){ outputSeqBuffer[i] = '\0'; } outputSeqBuffer[0] = ESC_CHAR; outputSeqBuffer[1] = '['; switch ( ESC_sequence[2] ) { case '6': // return Cursor Position sprintf(&outputSeqBuffer[2], "%d;%dR", cursorPos.cp_row + 1, cursorPos.cp_col + 1); break; case 'A': // return Auxillary Switch Status sprintf(&outputSeqBuffer[2], "%cR", vt100_get_auxSwitch()?'h':'l' ); break; case 'B': // return status of various attributes and parameters sprintf(&outputSeqBuffer[2], "%c;%c;%c;%c;%d;%cR", vt100_get_autoWrap()?'h':'l', vt100_get_autoScroll()?'h':'l', vt100_get_autoRepeat()?'h':'l', vt100_get_backLight()?'h':'l', vt100_get_backLightTimeout(), vt100_get_auxSwitch()?'h':'l'); break; default: break; } outBufLen = strlen(outputSeqBuffer); if( fdSerialPort > 0 ) { numBytesWritten = writeSerialPort(fdSerialPort, outputSeqBuffer, outBufLen ); if( numBytesWritten == outBufLen ) { ; // good command written out } else { ; // null statement - placeholder #if DEBUG_ON & DEBUG_SERIAL // ERR_07_PORT_WRITE if there was a return value printf("\n vt100_process_ESC_Seq: Only wrote %d of %d bytes to Serial port for CMD/RESP", numBytesWritten, outBufLen); #endif } } else { #if DEBUG_ON & DEBUG_SERIAL printf("\n vt100_process_ESC_Seq: write out to serial port %d chars:\n %s ", outBufLen, outputSeqBuffer); #endif } break; case SAVE_CURSOR_POS: vt100_save_cursorPos(); break; case REST_CURSOR_POS: vt100_rest_cursorPos(); break; default: break; } // end switch } // end if //printf("ESC%d|%d[%d;%d]", seqCode, seqValue, cursorPos.cp_row, cursorPos.cp_col); //vt100_dumpVD("process_ESC", seq++,"after ESC sequence"); } // end process_ESC_Seq