Arduino Playground is read-only starting December 31st, 2018. For more info please look at this Forum Post

4aos - a small OS on the UNO

Introduction - Overview - Commands - Sample app - Instructions - Source code

4aos - Fo(u)r Arduino Operating System

This project should make it possible to execute and edit little apps on the arduino. The real bottleneck of such a project is the limited RAM of 2 kB, so everything has to be quite squeezed (i.e. each app instruction is saved in a separate little file).

4AOS running on arduino

Requirements:

  • arduino uno Rev 3
  • default arduino compiler and installer
  • 320x240 TFT-touch-shield in 8-bit mode and without IRQ-pin

Getting started (with the gzipped file, see above):

  • unzip the downloaded file
  • just copy the content of the folder 'CopyContentToSd' to a clean 'fat-16' formatted sd-card,
  • insert the sd-card into your TFT-touch-shield,
  • open the '4aosV08b.ino' file as a sketch (check that your shield has the appropriate I/O-pin-configuration),
  • compile the sketch and install it on the arduino (eventually you have to change the values for touch input in the source code; in this case you may use https://playground.arduino.cc//Main/TouchscreenPainting ).

Manuals:

  • There are 2 short manuals in the 'MAN'-folder. 'man_4a' describes the basic OS commands, 'man_sb' provides an overview about the implemented instructions for apps.

If you want to read them directly on the arduino, type:

  • 'CD MAN'<ENTER> (changes the working directory)
  • 'OP MAN_4A'<ENTER> (selects -or opens- the file)
  • 'IT'<ENTER> (interprets the file as a text file)
  • tap the F1 key for further pages

License:

  • This project is published under the GNUv3-License. I'd like to thank the authors of the libs 'avr/pgmspace.h' and 'SD.h' as well as those of the code that enables touch-TFT access.

Please contact mknot9@gmail.com for remarks or ideas.

 

4AOS Overview

This is a quite squeezed version of a very basic 'operating system' since it has to fit within 32k and only 2k of RAM are available.

Therefore it can (in the moment;-) only be programmed in SOBAD (a Simple Open Basic Assembler Dialect;-) which is line-based with 3-byte instructions and one optional argument. See manuals for futher details.

4AOS provides a basic GUI 'around' the command line:

 _______
I_______I 1.
I       I
I       I 2.
I_______I
I    I  I 3.
I____I__I

  • 1. Status bar with present path on SD-card, number of files in present directory, NAME of 'open' file, free bytes of RAM (don't trust it too much, temoprarily sd-access reduces it nearly to 0!) and an activity indicator showing up on execution of 'long' instructions. A tap in this area clears and refreshes the whole display

  • 2. 12 Lines for commands and system messages (the last 6 'important' ones are buffered)

  • 3. Keypad on the left side; shift-, enter-, delete- and 2 function keys (F1=list/continue program/text, F2=additinal space-key/Escape-emulation for running apps) on the right side

Maybe this project helps some people who want to solve little programmable tasks 'on the go' without access to a PC. The usual way to work with 4AOS is:

  • 1. Navigating to the desired file e.g. NAME (with CD and LS)
  • 2. 'Open' the desired file (OP NAME)
  • 3. Work with / execute this file using SOBAD

Since the arduino provides only 2k RAM each SOBAD instruction is stored in its own file to prevent buffering issues. For export/import of apps the XP/IP-command is provided.

4AOS COMMANDS

All commands have to be typed directly after the '>'-prompt, exactly one space is needed before you enter an argument - no trailing spaces! Comments to the following examples start with a ':'

1.DIRECTORIES

LS=List Directory Items

  • LS :show the first entries
  • LS 4 :show the entries after the 4.

CD=Change Directory, only absolute paths (!), no leading & trailing slashes (!)

  • CD :to / (Root)
  • CD XY :to /XY/
  • CD XY/AB :to /XY/AB/

MD=Make Directory

  • MD NAME :Creates the directory 'NAME' and uses this as the present path

OP='Open' File

  • OP NAME :selects/creates (app) file 'NAME' to work with
  • OP :'deactivates' selection of this file

2.FILES (selected by 'OP')

RM=Remove File (or Directory)

  • RM :removes 'opened' file or last directory if it is empty, if a directory is removed the path is reset to root

FI=File Information

  • FI :returns length of selected file

HD=Head of file

  • HD :shows first 26 text-bytes of the selected file
  • HD 9 :shows the next 26 text-bytes after the 9.

HA=Head all bytes

  • HA :shows all ~15 bytes, beginning with non-text bytes in ASCII-code, position in file represented by a '`'
  • HA 8 :shows all ~15 bytes after the 8.

IT=Interpret as text file

  • IT :shows the first ~90 text-bytes (10 lines), continued with F1
  • IT 60 :shows the next text-bytes after the 60.

IP=ImPort Program

  • IP :converts file 'NAME' to SOBAD (see 'man_sb' ;-) format

XP=ExPort Program

  • XP :Converts and saves program in SOBAD format into file 'NAME'

GO=start program

  • GO :Execute program in SOBAD format

LP=List program

  • LP :Lists first 10 lines of program in SOBAD format, continued with F1
  • LP 804 :List next lines after line 804

SB=Switch activity Bar

  • SB :disables/enables activity bar while executing apps (saves some time)

XXX=Define program line=3 digits except leading '0', exactly one space is needed before the instruction

  • 238 GSB 800 :saves line 238 with instruction to call subroutine beginning at line 800
  • 482 :deletes line 482
  • 237 DSC :inserts new line (with 'Delete Screen'-command) between 236 and 238, shift as much lines above 238 as needed, store inserted line as 238 and change GTO/GSB lines if needed

Example of a short app in the SOBAD format (GX in the DMO/GFX folder)

  • You may also edit this on a PC, save it as a text file, copy it into a folder on the SD card, open it with 'OP GX' on the arduino and than import it as an executable small program with 'IP' and 'GO'. All lines that don't have a leading number will be ignored, so one-line comments are possible.

CODE:
100 DSC
Create color picker:
102 V5= 111
104 V1= -32560
106 CR= 113
108 V6= 1
110 V3= 3256
112 CT= CR
114 CT+ 4
116 CC= 6
118 V2= V3
120 V2* CA
122 V2+ V1
124 CS= CQ
126 CS+ 5
128 DPX V2
130 CQ+ CC
132 CA+ 1
134 V0= 20
136 I0> CA
138 GTO 112
Main loop:
140 CA= 8
142 V8= -1
144 GSB 200
146 CC= 4
148 DQG
150 I5> CR
152 GTO 302
154 NOP
Calculate new color and manage screen:
156 CB= CQ
158 V8= 0
160 GSB 200
162 V8= -1
164 CA= CB
166 CA/ 6
168 GSB 200
170 CR= 0
172 V2= CA
174 V2* V3
176 V2+ V1
178 GTO 148
Subroutine display color change:
200 CR= 118
202 CT= 119
204 CQ= CA
206 CQ* 6
208 CS= CQ
210 CS+ 5
212 DPX V8
214 RTN
302 I6> CR
304 GTO 148
Paint pixel:
306 CS= CQ
308 CS+ CC
310 CT= CR
312 CT+ CC
314 DPX V2
316 GTO 148

SOBAD instructions

This Simple Open Basic Assembler Dialect is based on even (!) 3 digit-line numbers (from 100, 102 to 998 - odd numbers are used in order to implement an 'insert' function for new lines), which is an easy way to save time and space ressources on arduino. Each program starts in line 100 and after each line 2 are added - except a GTO, GSB, RTN, Ifx, JMP or JMB (Goto, Gosub, Return, If, Jump or JumpBack) instruction is used.

Each instruction is exactly 3 bytes long, followed by an optional argument that is separated by one space. All arguments are interpreted as numbers or numeric variables except after the string instruction 'SWT'. In case of endless loops tapping 'F2' brings you back to the command line.

SOBAD provides several variables:

  • 20 8-bit integers (CA to CT)
  • 10 16-bit integers (V0 to V9)
  • 2 strings of 25 bytes each (SW and SU)
  • 1 array of 20 16-bit integers who can be 'pointed' by the values of the 8-bit integers, so AA to AT are valid if their value is 0-19)

Access to numeric variables is defined by a 3-byte code: 'TIO arg' = Type, Identifier, Operation followed by an argument. Possible types are:

  • C for the 8 bit integer followed by the identifiers A to T ('C-registers')
  • V for the 16 bit integer, identifier 0 to 9 ('V-registers')
  • A for the array followed by A to T for the 8 bit register that represents the pointer ('A-registers')

Possible operations on the defined registers are:

  • = for new value
  • + for add to register
  • - for subtract from register
  • the multiplier for the register is *
  • / divides the register

Examples:

  • CK= 12 puts 12 in the 8 bit register CK
  • AK+ 1 adds one to array element 12 if 12 is still the value of CK
  • AT- V6 subtracts the value of the 16 bit register no. 6 from the array element pointed by CT

Input and output:

  • 'DSC' Delete SCreen Content (Clear)
  • 'D(A-S)G' Get Touch coordinates: x(0-119)=> C-register, y(0-119)=>C+1-register
  • 'DPX arg' Draws PiXeL block with values of CQ-CT [0-119] (x1=CQ, y1=CR, x2=CS, y2=CT, argument=color of pixel block); 0,0 means upper left corner
  • 'DLY arg' DeLaY in milliseconds = arg
  • 'DIP arg' Defines Pin arg as an Input Pin (although its possible: never touch the pin states used for the TFT/SD!)
  • 'DOP arg' Define Pin arg as Output Pin
  • 'DHP arg' writes a Digital HIGH on Pin arg
  • 'DLP arg' writes a Digital LOW on Pin arg
  • 'D(0-9)R arg' reads the Digital input value of Pin arg into V0-9
  • 'D(0-8)T' reads Digital Runtime in s, h and ms: sec (0-3600)=> V-register, hours (0-128)=> corresponding C-register (A-J), ms (0-999)=> V+1-register
  • 'END' stops the execution (last value of string W is printed by default)

Branching and jumping:

  • 'I(0-9)(>=<) arg' If value of V-register is > xor = xor < arg execute next line, otherwise skip next line
  • 'GTO arg' GoTO line=arg (equal number 100-998 or register for advanced programmable jumps)
  • 'GSB arg' GoSuB line=arg (equal number 100-998 or register value, 10 Levels of jumps are provided, where line number+2 is cached)
  • 'RTN' ReTurN from subroutine
  • 'V(0-9)L' saves the actual programm line in V-Register (0-9)

Library linking:

  • 'JMP arg' JuMP to line number in other directory & file in the 'LIB'-directory (library for often used functions). The name of subdirectory & file has to be identical and is defined in string U. The line number is defined by value of arg (this is a quite advanced option, since both 'programs' work with the same registers and you have to implement the 'back' jump line explicitly.
  • 'JMB arg' JuMp Back to line number of the original app after execution of the app in the 'LIB' directory.

The following string operations are available:

  • 'SWT arg' adds Text to W-String (arg=up to 15 CAPITALS/DIGITS)
  • 'SWN arg' adds numeric value interpreted as text to W-String (arg=-32768 to 32767 or AA to V9)
  • 'SUW' place string W behind U and save it in U
  • 'SWU' or vice versa
  • 'S(0-9)L' puts string length of W in v-register, e.g. if W has a length of 3 S6L writes this value to V6
  • 'SWD' deletes String W
  • 'SUD' deletes String U
  • 'SWR arg' defines row No. (arg=1-11) where string W will be placed
  • 'SWX arg' defines x-value (arg=0-119) where string W will be placed
  • 'SWP arg' prints string W in defined line of the display, the argument for the size is optional (1-4, 2 is default)
  • 'SWS' appends value of String W in a file named correspondig to the app abbreveation followed by a 4 by default, if an argument 10-99 is added this file will also be created (even numbers mean the string is added, odd numbers: file is overwritten)

Hello world (assuming you are in the root directory):

  • MD HEWO :Creates the app directory 'HEWO', this directory is the new path by default
  • OP HW :Creates the app file and name; if its a new file the first app line (100) will appear
  • 100 SWT HI WORLD :'HI WORLD' is saved in string W
  • 102 END :stops the app and prints the value of string W
  • GO :executes the app (and always creates a log-file 'HW4' with the default content 'LOG<CR><LF>')

Further steps:

  • 101 SWS :inserts a line between 100 and 102, saves it as a new line 102, shifts the other lines by 2 as far as needed and increments all direct GTO/GSB instructions by 2, now during app execution 'HI WORLD' is added to file HW4
  • XP :'exports' and converts the app as a text file an saves it in 'HW' overriding previous content. This is useful if you want to share apps with others.
  • IP :'imports' and converts the app to the SOBAD format overriding previous content. This is useful if you want to use other apps in SOBAD. You may also write listings with a text editor, save them in a directory on a SD card and execute them on an arduino.

Source Code

For all those who just want to try the code, not the examples, here it is (compiling results in 31960 bytes, so there's still some place for new ideas ;-)

#include <SD.h>
#include <avr/pgmspace.h>
// Thanks to the authors of the libs 'avr/pgmspace.h' and 'SD.h' as well as those of the code that enables touch-TFT access and FreeR1.
// This project is published under the GNUv3-License. Please contact mknot9@gmail.com for remarks or ideas.

#define SDIN     11

#define LCD_RS   19
#define LCD_WR   18
#define LCD_CS   17
#define LCD_REST 16

#define DCLK     15
#define DIN      14
#define CS       10
#define DOUT     8
//#define IRQ 7, #7 is depreceated on some shields, here DOUT is used as #8 (PIN 12 & 13 -> SD-SPI!)

File root;

unsigned int TP_X,TP_Y;//touch feedback from driver
unsigned char staOcu=1,errOcu=0,couOcI=0; // cursor handling: staTEoFcuRSOR (0,1), errORoFcuRSOR (0,1), couNToFcURSORiNTERVAL (0-9), s.a. ConCur()
char actBar=0, lineFeedFlag, shiftFlag=0; // action bar (in)-active while app execution (0,1), indicates that command line has 2 lines (0,1), indicates if shift was tapped (0,33)
char nm[12],em[5]={"ERR "}, dt[12]={""}, h5[31], pat[20]; // Arrays for line numbers/file name on JMP, error message, present file name, command line, path
char z3, z5, h3[22]; // start and end of text to be written, multi-used caching string 
char hf4=0,ei,e2,e3,e4; // dual used global: indicates 28 chars in DirRead or 8 byte representation of app argument, multi-used chars for input interpretation
char yc=0,sk=2,tc=5,hc=0,gc,l9=0,l8=0; // Count screen lines, scaling factor of text, counter of buffer line, counter for input length, counter for gosub level, position of activity bar, shortcut support for IT-command
char ts[90]={""}, c3[20],h6[31]={""},h8[31]={""},h4[31]={""}; //buffer for screen, array for app integer (-128 to 127), 3 multi used caching strings 
int x2, y2, f1, f2, fc=0,y4=11, vh2=0x01,vl2=0x08; //position of cursor, multi used vars
int lx,ly, a3[20], v3[10], g3[10], l2, l3,l4,l6,l5=0, ry,rx,x3=0,y3; //position of touch tap, arrays for app variables and multi used integers
PROGMEM prog_char tp[]={">SHIFT>ENTER>_DEL_F1  F2"}; // just a basic GUI
PROGMEM prog_char ko[]={0,0,1,5, 0,5,1,9, 1,0,6,1, 1,4,6,5, 1,8,6,9, 6,0,7,5,6,5,7,9}; //lots of vectors in order to display ASCII characters
PROGMEM prog_char mo[]={13,1,3,5, 13,-1,6,0, 6,0,7,9, 13,1,0,0, 0,0,1,9, 13,-1,3,5, 3,8,4,9, 3,0,7,1, 9,9,9,9, 2,5,7,6, 6,1,7,2, 2,3,7,4, 3,3,4,4, 0,0,7,1, 16,-1,6,1, 3,0,4,9, 0,8,7,9, 4,3,5,8, 12,-1,5,6, 13,-1,6,3, 12,1,3,0, 12,-1,3,0, 11,-1,3,6, 15,1,1,2, 13,-1,4,3, 5,2,6,7, 13,1,0,3, 2,0,3,3, 4,0,5,3, 3,2,4,7, 1,2,2,7, 11,1,2,7, 5,7,6,8, 14,-1,6,3, 3,8,7,9, 9999};
//x98=lots of vectors  8=<space> !   "    #   $   %  &    '   (    )    *   +   ,   -   .    /  0   1   2   3  4   5 6  7   8 9   :   ;    <     =    >   ?    @  A  B    C   D   E   F    G    H  I    J     K    L    M      N    O P  Q    R    S     T   U   V     W   X     Y    Z    [    \  ]    ^   _   `  ~
PROGMEM prog_int16_t zo[]={8,30078,12009,198,298,398,498,2009,598,13809,698,919,109,19,6008,69,694,4079,17,12,235,26,6,1245,0,2,4978,5049,4909,139,3209,798,19470,5,286,4670,5468,670,567,19460,35,8579,134,28356,3467,24358,14358,40,57,1840,1857,29260,579,34,2658,15368,16248,2648,8659,898,609,998,3409,89,309,9019};
PROGMEM float uo[]={98,3080139,79260,670049,7563409,540409,700919,407828,8007988,800838}; // vectors for characters that aren't easy to display

void spistar()                                   //usual TFT-touch driver... SPI Start
{
  digitalWrite(CS,LOW);
  digitalWrite(DCLK,HIGH);
  digitalWrite(DIN,HIGH);
  digitalWrite(DCLK,HIGH);
}
//**********************************************************
void WriteCharTo7843(unsigned char num)          //SPI Write Data to Touch
{
  unsigned char count=0;
  unsigned char temp;
  unsigned nop;
  temp=num;
  digitalWrite(DCLK,LOW);
  for(count=0;count<8;count++)
  {
    if(temp&0x80)
      digitalWrite(DIN,HIGH);
    else
      digitalWrite(DIN,LOW);
    temp=temp<<1;
    digitalWrite(DCLK,LOW);
    nop++;
    nop++;
    digitalWrite(DCLK,HIGH);
    nop++;
    nop++;
  }
}
//**********************************************************
unsigned int ReadFromCharFrom7843()             //SPI Read Data from Touch
{
  unsigned nop;
  unsigned char count=0;
  unsigned int Num=0;
  for(count=0;count<12;count++)
  {
    Num<<=1;
    digitalWrite(DCLK,HIGH);//DCLK=1; _nop_();_nop_();_nop_();
    nop++;
    digitalWrite(DCLK,LOW);//DCLK=0; _nop_();_nop_();_nop_();
    nop++;
    if(digitalRead(DOUT)) Num++;
  }
  return(Num);
}

void LCD_Writ_Bus(char VH,char VL)
{
  PORTD = VH;
  digitalWrite(LCD_WR,LOW);
  digitalWrite(LCD_WR,HIGH);
  PORTD = VL;
  digitalWrite(LCD_WR,LOW);
  digitalWrite(LCD_WR,HIGH);
}

void LCD_Write_COM(char VH,char VL)
{
  digitalWrite(LCD_RS,LOW);
  LCD_Writ_Bus(VH,VL);
}

void LCD_Write_DATA(char VH,char VL)
{
  digitalWrite(LCD_RS,HIGH);
  LCD_Writ_Bus(VH,VL);
}

void Lcd_Write_Com_Data(int com,int val)
{
  LCD_Write_COM(com>>8,com);
  LCD_Write_DATA(val>>8,val);
}

void Address_set(unsigned int x1,unsigned int y1,unsigned int x2,unsigned int y9)
{
  LCD_Write_COM(0x00,0x46);LCD_Write_DATA(x2,x1);
  LCD_Write_COM(0x00,0x47);LCD_Write_DATA(y9>>8,y9);
  LCD_Write_COM(0x00,0x48);LCD_Write_DATA(y1>>8,y1);
  LCD_Write_COM(0x00,0x20);LCD_Write_DATA(x1>>8,x1);
  LCD_Write_COM(0x00,0x21);LCD_Write_DATA(y1>>8,y1);
  LCD_Write_COM(0x00,0x22);
}

void LCD_Init(void)
{
  digitalWrite(LCD_REST,HIGH);
  delay(5);
  digitalWrite(LCD_REST,LOW);
  delay(5);
  digitalWrite(LCD_REST,HIGH);
  delay(5);
  digitalWrite(LCD_CS,LOW);

  Lcd_Write_Com_Data(0x11,0x2004);Lcd_Write_Com_Data(0x13,0xCC00);Lcd_Write_Com_Data(0x15,0x2600);

  Lcd_Write_Com_Data(0x14,0x252A);Lcd_Write_Com_Data(0x12,0x0033);Lcd_Write_Com_Data(0x13,0xCC04);
        delay(1);Lcd_Write_Com_Data(0x13,0xCC06);
        delay(1);Lcd_Write_Com_Data(0x13,0xCC4F);
        delay(1);Lcd_Write_Com_Data(0x13,0x674F);
        Lcd_Write_Com_Data(0x11,0x2003);delay(1);
  Lcd_Write_Com_Data(0x30,0x2609);Lcd_Write_Com_Data(0x31,0x242C);Lcd_Write_Com_Data(0x32,0x1F23);

  Lcd_Write_Com_Data(0x33,0x2425);Lcd_Write_Com_Data(0x34,0x2226);Lcd_Write_Com_Data(0x35,0x2523);

  Lcd_Write_Com_Data(0x36,0x1C1A);Lcd_Write_Com_Data(0x37,0x131D);Lcd_Write_Com_Data(0x38,0x0B11);

  Lcd_Write_Com_Data(0x39,0x1210);Lcd_Write_Com_Data(0x3A,0x1315);Lcd_Write_Com_Data(0x3B,0x3619);

  Lcd_Write_Com_Data(0x3C,0x0D00);Lcd_Write_Com_Data(0x3D,0x000D);Lcd_Write_Com_Data(0x16,0x0007);

  Lcd_Write_Com_Data(0x02,0x0013);Lcd_Write_Com_Data(0x03,0x0003);Lcd_Write_Com_Data(0x01,0x0127);
        delay(1);

  Lcd_Write_Com_Data(0x08,0x0303);Lcd_Write_Com_Data(0x0A,0x000B);Lcd_Write_Com_Data(0x0B,0x0003);

  Lcd_Write_Com_Data(0x0C,0x0000);Lcd_Write_Com_Data(0x41,0x0000);Lcd_Write_Com_Data(0x50,0x0000);

  Lcd_Write_Com_Data(0x60,0x0005);Lcd_Write_Com_Data(0x70,0x000B);Lcd_Write_Com_Data(0x71,0x0000);

  Lcd_Write_Com_Data(0x78,0x0000);Lcd_Write_Com_Data(0x7A,0x0000);Lcd_Write_Com_Data(0x79,0x0007);
        Lcd_Write_Com_Data(0x07,0x0051);delay(1);

  Lcd_Write_Com_Data(0x07,0x0053);Lcd_Write_Com_Data(0x79,0x0000);LCD_Write_COM(0x00,0x22);
  digitalWrite(LCD_CS,HIGH);
}

void AD7843(void)
{
  digitalWrite(CS,LOW);
  WriteCharTo7843(0x90);
  digitalWrite(DCLK,HIGH);
  digitalWrite(DCLK,LOW);
  TP_Y=ReadFromCharFrom7843();
  WriteCharTo7843(0xD0);
  digitalWrite(DCLK,HIGH);
  digitalWrite(DCLK,LOW);
  TP_X=ReadFromCharFrom7843();
  digitalWrite(CS,HIGH);              // end of usual 8-bit TFT & Touch Driver
}

int freeR1()                          // thanks to arduino.cc!
{
  extern int __heap_start, *__brkval;
  int v;
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}

void PaiRec(int a1, int b1, int a2, int b2)  // paints rectangle relative to globals x2,y2 with scaling factor sk and color f1,f2; 240*273 shouldn't be exceeded
{
  unsigned int p3;
  Address_set(x2+a1*sk,y2+b1*sk,x2+a2*sk-1,y2+b2*sk-1);
  for(p3=0; p3<=((a2-a1)*sk*(b2-b1)*sk); p3++) LCD_Write_DATA(f1,f2);
}

void ConCur()  // controls cursor and error feedback for first or last character exceeding the supported input of 29 chars
{
  char i3=0;
  f1=staOcu*16;
  if (errOcu > 0)
  {
    errOcu--;
    f1=staOcu*224;
    i3=9;
  }

  f2=f1;
  digitalWrite(LCD_CS,LOW);
  if (staOcu > 0) PaiRec(0,9-i3,8,10);
  else PaiRec(0,0,8,10);
  digitalWrite(LCD_CS,HIGH);
  staOcu=1-staOcu;
  f1=255;
  f2=255;
}

void OneColor(int w1,int v1, int w2, int v2, char c1, char c2) // Colors a bigger area in One color depending on the paramater c1 & c2
{
  int i3,j3;
  digitalWrite(LCD_CS,LOW);
  Address_set(w1,v1,w2,v2);
  for(i3=v1;i3<=v2;i3++) for (j3=w1;j3<=w2;j3++) LCD_Write_DATA(c1,c2);
  digitalWrite(LCD_CS,HIGH);

}

void ActivityBar(char c) // indicates Activity in the status Bar that takes some time
{
  OneColor(220+l9,8,224+l9,8,0xFF,0xE0);
  l9=l9+4;
  if (l9>15) l9=0;
  OneColor(220+l9,8,224+l9,8,c*0xFF,c*0xE0);
}

void ResetInputControl()  // Resets Input Control strings h5 and h8
{
      strcpy (h5, ">");
      if (e2==124) {strcat(h5,nm); nm[0]='\0';}
      strcpy (h8, h5);
      z5=strlen(h5);
      hc=z5;
      x3=0;
      z3=0;
      lineFeedFlag=0;
}

void ShowStatus()   // Shows the present Status of working directory, no. of items, 'open' file and free RAM
{
  int xh,yh,zh,zg;
  int i,j,h;
  char h0[16];

  strcpy(h0,h5);
  OneColor(0,0,239,9,0x00,0x00);
  f2=0xE0;
  h4[0]='\0';
  OpenPathAndReadItems();
  zg=z5;
  yh=y3;
  xh=x3;
  zh=z3;
  h=x2;

  strcpy(h5, pat);
  strcat(h5," ");
  itoa(fc,h3,10);
  strcat(h5,h3);
  strcat(h5," ");
  if (dt[0]=='\0') strcat(h5,"-");
  else
  {
    j=strlen(h5);
    if (j+strlen(dt)>24)
    {
      for(i=0;i<6;i++) h5[j+i]=dt[i];

      h5[j+i]='.';
      h5[j+i+1]='.';
      h5[j+i+2]='\0';
    } else strcat(h5,dt);
  }
  strcat(h5," ");
  itoa(freeR1(),h3,10);
  strcat(h5,h3);
  j=strlen(h5);
  x3=0;
  z3=0;
  z5=j;

  sk=1;
  PrintAsciis(0);
  sk=2;

  OneColor(8*j+8,8,239,8,f1,f2);

  f2=0xFF;
  strcpy(h5,h0);
  z5=zg;
  y3=yh;
  x3=xh;
  z3=zh;
  x2=h;
}

void PrintAsciis(int z4) // Prints the content of h5 from z3 to the end at y-value z4
{
  long int p, h1, h2;
  int i, j, n, k9,t1,t2;
  char m0,m1,m2,m3;
  digitalWrite(LCD_CS,LOW);
  x2=x3;
  y2=z4;
  t1=f1;
  t2=f2;
  for(i=z3;i<z5;i++)
  {
   if ((h5[i]!='\0') && (h5[i]!='}'))
   {
    j=h5[i]-32;
    if ((j>94) || (j<0)) j=64;
    if ((j>64) && (j<94)) j=j-32;
    if (j==94) j=65;

    p=pgm_read_word_near(zo + j);
    h1=p/100;
    h2=p-h1*100;
    if (h2==98) p=pgm_read_float(uo + h1);
    h1=p/10;
    h1=p-h1*10;

    if ((h1==8)||(h1==9))
    {
      if (h1==8)  p=p/10;
    }
    else
    {
      for(j=0;j<28;j=j+4)
      {
          m0=pgm_read_byte_near(ko + j);
          m1=pgm_read_byte_near(ko + j +1);
          m2=pgm_read_byte_near(ko + j +2);
          m3=pgm_read_byte_near(ko + j +3);
          PaiRec(m0,m1,m2,m3);
      }

      f1=0x00;
      f2=0x00;

      if ((h1==0) && (p!=0))
      {
        PaiRec(0,0,1,1);
        PaiRec(6,0,7,1);
        PaiRec(0,8,1,9);
        PaiRec(6,8,7,9);
        p=p/10;
      }

      for(k9=0;k9<6;k9++)
      {
        h1=p/10;
        h1=p-h1*10;
        if ((h1==0)||(h1==8)||(h1==9))
        {
          if ((h1==8)) p=p/10;
          k9=6;
        }
        else
        {
          p=p/10;
          h1=(h1-1)*4;
          m0=pgm_read_byte_near(ko + h1);
          m1=pgm_read_byte_near(ko + h1 +1);
          m2=pgm_read_byte_near(ko + h1 +2);
          m3=pgm_read_byte_near(ko + h1 +3);
          PaiRec(m0,m1,m2,m3);
        }
      }
    }
    f1=t1;
    f2=t2;
    n=0;

    for(k9=0;k9<9;k9++)
    {
      h1=p/10;
      h1=p-h1*10;
      p=p/10;
      if ((h1==0) && (p==0)) k9=9; else
      {
        if ((h1==0) ||((h1==9)&&(n==0)))
        {
          if ((h1==0)&&(n==0)) n++;
          n++;
        }
        else
        {
          h1=(h1-1)*4+36*n;

          m0=pgm_read_byte_near(mo + h1);
          m1=pgm_read_byte_near(mo + h1 +1);
          m2=pgm_read_byte_near(mo + h1 +2);
          m3=pgm_read_byte_near(mo + h1 +3);

          if (m0>8)
          {
            for(j=0;j<m0-9;j++) PaiRec(m2+j*m1,m3+j,m2+j*m1+1,m3+j+1);
            if ((m3==0) && (n==0)) PaiRec(3,4,4,5);
          }
          else PaiRec(m0,m1,m2,m3);
        }
      }
    }
    x2=x2+8*sk;
    if (x2+8*sk>240)
    {
     x2=0;
     y2=y2+10*sk;
    }
   } else i=99;
  }
  digitalWrite(LCD_CS,HIGH);
  f1=t1;
  f2=t2;
  y3=y2;
  x3=x2;
  z3=i;
}

void ResetCommandLine()  // Resets Command Line on start or tap in status bar
{
  unsigned char i,j;
  OneColor(0,0,239,319,0x00,0x00);
  OneColor(0,251,239,251,0xE0,0xE0);
  OneColor(0,319,239,319,0xE0,0xE0);
  f1=16;
  f2=f1;
  z5=6;
  sk=1;
  for (i=0;i<4;i++)
  {
    for (j=0;j<6;j++)
    {
      h5[j]=pgm_read_byte_near(tp+i*6+j);
    }
    h5[6]='\0';
    x3=190;
    z3=0;
    PrintAsciis(254+i*18);
  }
  sk=2;
  ShiftKeys();
  if (strlen(pat)<2) strcpy(h5,"4AOS:SD OK!");
  else strcpy(h5,pat);
  x3=0;
  z3=0;
  z5=strlen(h5);
  PrintAsciis(11);

  ShowStatus();

  hc=1;
  x3=0;
  z3=0;
  z5=1;
  yc=1;
  strcpy(h5,">");
  strcpy(h8,h5);
  PrintAsciis(31);
  lineFeedFlag=0;
}

void ShiftKeys() // displays the 'other' ascii characters (simulates the 'shift'-key on ordinary keyboards)
{
  int xh,yh;
  unsigned char p,i,j,h,zg,zh;
  OneColor(0,252,180,318,0x00,0x00);
  strcpy(h4,h5);

  shiftFlag=33-shiftFlag;
  f1=6;
  f2=224;

  zg=z5;
  yh=y3;
  xh=x3;
  zh=z3;
  h=x2;
  z5=11;
  for (i=0;i<3;i++)
  {
    for (j=0;j<11;j++)
    {
         p=32+shiftFlag+i*11+j;

         if (p==32) p=126;
         if (p==96) p=32;
         if (p==47) p=96;
         if (p==97) p=47;

         h5[j]=p;
     }
   h5[11]='\0';
   x3=0;
   z3=0;
   PrintAsciis(254+i*22);
 }

  f1=255;
  f2=f1;
  y3=yh;
  y2=yh;
  x3=xh;
  z3=zh;

  x2=h;
  z5=zg;
  strcpy(h5,h4);
 }

void ReadAndCountDirItems(File dir)  // Reads And Counts the Items of Dir, starting to read at the l5.th, up to 26 chars 
{
  char h9[31]={""};
  char h10[12];
  fc=0;
  hf4=0;
//  if (strlen(pat)<2) dir.rewindDirectory();
  dir.rewindDirectory();


  while(true)
  {
    File entry =  dir.openNextFile();
    if (! entry) break;                      // no more files
    if (l5<=fc)
    {
      if (hf4 < 1)
      {
        h10[0]='\0';
        strcat (h10, entry.name());
        if ( strlen(h10)+strlen(h9) > 26) hf4=1;
        else
        {
          strcat (h9, entry.name());
          if (entry.isDirectory())
          {
            strcat (h9, "/");
          }
          strcat (h9, " ");
        }
      }
    }
    entry.close();
    fc++;
  }
  strcpy (h4, h9);
  l5=0;
}

void PrintLineToDisplayAndBuffer() // displays present Command Line and saves it in Buffer, also checks if new page is needed
{
          SaveCommandLineInBuffer();
          hc=strlen(h5);
          if (h5[hc]==125) hc--;
          z5=hc;
          PrintAsciis(y4+yc*10*sk);
          yc++;
          if (yc>11) ClearDisplayAndPrintBuffer();
}

void SaveCommandLineInBuffer()  // Saves present Command Line In Buffer
{
   unsigned char p=0;
          tc++;
          if (tc>5) tc=0;
          for (p=0;p<strlen(h5);p++) ts[p+15*tc]=h5[p];
}

void SendCommandLineToScreen()  // Prepares the Command Line to be Written
{
              z5=strlen(h5);
              PrintAsciis(y4+yc*10*sk);
              yc=yc+(sk+1)/2;
              z3=0;
              x3=0;
}

void ClearDisplayAndResetControlVariables()  // Clears the Screen and resets the Controls
{
            OneColor(0,9,239,250,0x00,0x00);
            hc=0;
            yc=0;
            z3=0;
            x3=0;
}

void ClearDisplayAndPrintBuffer()  // called when Display is full
{
  unsigned char p;
  OneColor(0,9,239,250,0x00,0x00);
  ShowStatus();

  l3=tc;
  hc=0;
  yc=0;

  for(p=0;p<6;p++)
  {
    l3++;
    if (l3>5) l3=0;
    for(hc=0;hc<16;hc++)
    {

      if ((ts[l3*15+hc] != '}')&&(hc<15))
      {
        h5[hc]=ts[l3*15+hc];
      }
      else
      {
        h5[hc]='\0';
        z5=hc;
        z3=0;
        x3=0;
        y3=y4+10*sk*yc;
        PrintAsciis(y3);
        hc=16;
      }
    }
    yc++;
  }
}

void OpenPathAndReadItems()  // Opens Path 'pat' and reads the dir items
{
  pinMode(DOUT,OUTPUT);
      root = SD.open(pat);
      ReadAndCountDirItems(root);
      root.close();
  pinMode(DOUT,INPUT);
}

void WriteToFile(char d8) // Writes Content of h4 in path&file h6, overriding on parameter 0, success sets e4=1
{
                  if ((SD.exists(h6)) && (d8==0)) SD.remove(h6);
                  e4=0;
                  root = SD.open(h6, FILE_WRITE);
                  if (root)
                  {
                    root.println(h4);
                    root.close();
                    e4=1;
                  }
}

void ConcatPathWithFileAndNumber(int l1)  // Prepare Path for File Access with Line Number
{
                itoa(l1,h3,10);
                strcpy(h6,pat);
                strcat(h6,dt);
                strcat(h6,h3);
}

void ReadFromFile()     // Reads the next 29 (displayable) bytes from file specified in h6, from position l5, new position is saved in l6
{
   unsigned char p=0;
                l6=l5;
                root = SD.open(h6);
                root.seek(l5);
                while ((root.available()) && (p<29)&& (l6<32766)&& (l5<32766))
                {
                  l6++;
                  h4[p]=root.read();
                  if ( ((h4[p]==10)||(h4[p]==13)) && (ei=='I') ) {l5=32766;p--;}
                  if ( ( (h4[p]<127) && (h4[p]>31) ) || (e2=='A') )  p++;
                }
                root.close();
                h4[p]='\0';
                l5=0;
}

void GetXYfromTouchcreen()  // Reads the present values from Touchscreen 
{
  unsigned char p;
  rx=0;
  ry=0;
  for(p=0;p<8;p++)      // check 8 times to reduce noise
    {
      AD7843();

      lx=0;
      ly=-1*TP_Y;
      ly=4095+ly;                               //4095=base for y-value, check for differences with your individual touch-shield!
      if(ly > 0) lx=1*TP_X; else {lx=0;ly=0;rx=0;ry=0;p=9; }
      rx=rx+lx;
      ry=ry+ly;
    }
  lx=(rx/8-180)/15;                               //reduces x-value to 239 max, check for your shield
  ly=(ry/8-240)/11;                               //reduces y-value to 319 max, check for your shield
  if ((ly < 1) || (lx < 1)) {lx=0;ly=0; }
}

void setup()
{
  unsigned char p;

  for(p=0;p<20;p++) pinMode(p,OUTPUT);
  pinMode(SDIN,INPUT);

  for(p=0; p<90; p++) ts[p]=32;
  ts[p]='\0';

  LCD_Init();

  strcpy(pat,"/");
  pinMode(DOUT,OUTPUT);
  if (!SD.begin(10)) strcpy(pat,"NO SD!");

  pinMode(DOUT,INPUT);

  ResetCommandLine();
  spistar();
}

void loop()
{
  e2=0;
  GetXYfromTouchcreen();
  if ((ly > 0) && (ly<6)) ResetCommandLine();
  if (ly > 250)
  {
    if (lx<66)
    {
      if ((ly>305))
      {
        if (lx<33)
        {
          strcat(h5," ");
          strcat(h8," ");
          hc=hc++;
          z5=z5++;
        }
        else
        {
          ly=269;
          if (l8<1) strcpy(h8,">LP "); else strcpy(h8,">IT ");
          if (nm[0]!='\0') {strcat(h8,nm);nm[0]='\0';}
        }
      }
      l8=0;

      if (ly<266) ShiftKeys();

      if ((ly>265) && (ly<281))
      {
        ei=h8[1];
        e2=h8[2];
        staOcu=0;
        ConCur();
//        strcpy(h4,h8);
        h6[0]='\0';
        l4=4;
        if ((ei>47) && (ei<58)) l4=5;
        for (l2=l4;l2<strlen(h8);l2++) h4[l2-l4]=h8[l2];
        h4[l2-l4]='\0';


        if ((ei>47) && (ei<58) )
        {
         if (strlen(dt)<1) strcpy(h4,"FILE?");
         else
         {
          h3[0]=ei;
          h3[1]=e2;
          h3[2]=h8[3];
          h3[3]='\0';
          l3=atoi(h3);
          pinMode(DOUT,OUTPUT);
          if (strlen(h4)<1)      // Delete line no w/o text
          {
            ConcatPathWithFileAndNumber(l3);
            if (SD.exists(h6)) SD.remove(h6);
            ShowStatus();
            strcpy(h4,"OK");
          } else
          {
            strcpy(h8,h4);
            if ((l3/2)*2 != l3)  // If its an odd line no, first search for the next free one => put it in l2 
            {
              l2=l3-1;
              while (((l3/2)*2 != l3) && (l2<999))
              {
                l2=l2+2;
                ConcatPathWithFileAndNumber(l2);
                if (! SD.exists(h6)) l3++;
              }
              l4=998;
              while (l4>98)
              {
               ActivityBar(0);
               ConcatPathWithFileAndNumber(l4-2);
               if (SD.exists(h6))
               {
                l5=0;
                ReadFromFile();
                f1=0;
                if ((h4[0]=='G') && (h4[4]>48) && (h4[4]<58) )
                {
                  h3[0]=h4[4];
                  h3[1]=h4[5];
                  h3[2]=h4[6];
                  h3[3]='\0';
                  l6=atoi(h3);
                  if ((l6>=l3) && (l6<l2))
                  {
                    l6=l6+2;
                    itoa(l6,h3,10);
                    h4[4]=h3[0];
                    h4[5]=h3[1];
                    h4[6]=h3[2];
                    h4[7]='\0';
                    f1=1;
                  }
                }
                if ( (f1==1)  || ((l4>l3) && (l4<=l2)) )
                {
                  f2=l4;
                  if (( l4<l3) || (l4>l2)) f2=f2-2;

                  ConcatPathWithFileAndNumber(f2);
                  WriteToFile(0);

                }
                f2=255;
                f1=255;
               }
               l4=l4-2;
              }
            }
            ConcatPathWithFileAndNumber(l3);
            strcpy(h4,h8);
            WriteToFile(0);
            if (e4==1)
            {
              e2=124;
              l2=atoi(h3);
              l2=l2+2;
              itoa(l2,nm,10);
              ShowStatus();
              h4[0]='\0';
            } else strcpy(h4,em);
          }
          h6[0]='\0';
          pinMode(DOUT,INPUT);
         }
        }

        if ((ei=='G') && (e2=='O'))
        {
          SendCommandLineToScreen();
          if (yc>11) ClearDisplayAndPrintBuffer();
          z3=0;
          x3=0;
          l3=100;      // defines inital line

          for (l2=0;l2<10;l2++)
          {
            v3[l2]=0;
            c3[l2]=0;
            c3[l2+10]=0;
            a3[l2]=0;
            a3[l2+10]=0;
          }

          ConcatPathWithFileAndNumber(4);
          strcpy(h4,"LOG");
          WriteToFile(0);
          gc=0;
          hc=0;
          h5[0]='\0';
          h8[0]='\0';
          while (ei=='G')
          {
            if (actBar) ActivityBar(0);
            ConcatPathWithFileAndNumber(l3);

            l3=l3+2;            // prepare next line
            pinMode(DOUT,OUTPUT);
            if (SD.exists(h6))
            {
              l5=0;
              ReadFromFile();
              h3[0]='\0';
            } else
            {strcat(h3,":?");strcpy(h4,"END");}
            pinMode(DOUT,INPUT);

            for (l2=4;l2<strlen(h4);l2++) h6[l2-4]=h4[l2];
            h6[l2-4]='\0';
            e3=h4[0];
            e4=h4[1];
            e2=h4[2];
            l6=0;

//            if ((e3=='S') && (e4=='U') && (e2=='T') ) strcpy(h8,h6);    // depreceated for space reasons: use SWT & SUW
            if ((e3=='S') && (e4=='W') && (e2=='T') ) strcpy(h3,h6);      // add Text to String W
            else if (h6[0]=='V') l6=v3[h6[1]-48];
              else if (h6[0]=='C') l6=c3[h6[1]-65];
                else if (h6[0]=='A') l6=a3[c3[h6[1]-65]];                 // convert a,c or v-Variable or integer in 16 byte int
                  else l6=atoi(h6);
            hf4=1*l6;                                                     // save argument as 8 byte int for later purposes
            l4=e4-48;
            l5=l4-17;                                                     // save as index pointers for register access

            if ((e3=='J') && (e4=='M')  )        // switch to other dir&file with arg=line no. for lib defined in string U, present file name is saved in string U 
            {
              if (e2=='P')
              {
                strcpy(nm,dt);
                strcpy(h6,pat);
                strcpy(pat,"/LIB/");
                strcat(pat,h8);
                strcat(pat,"/");
                strcpy(dt,h8);
                strcpy(h8,h6);
                l3=l6;             
              } else
              {
                strcpy(pat,h8);
                strcpy(dt,nm);
                l3=l6;             
              }             
            }

            if (e3=='S')
            {
              if (strlen(h5)+strlen(h8)<29)
              {
                if ( (e4=='U') && (e2=='W') ) strcat(h8,h5);      // concat W to U-String or vice versa

                if ( (e4=='W') && (e2=='U') ) strcat(h5,h8);
              }

              if (e2=='L')  v3[l4]=strlen(h5);                // String Length of W in v-register

              if ( (e4=='U')&& (e2=='D') ) h8[0]='\0';          // Delete String U

              if (e4=='W')
              {             
                if (e2=='N') itoa(l6,h3,10);     // concat numeric to String W

                if (e2=='D') h5[0]='\0';          // Delete String W

                if (e2=='R') yc=hf4-1;             // Set screen Ror (1-10) for next printing 

                if (e2=='X') x3=hf4*2;             // Set screen x-value (0-119) for next printing 

                if (e2=='P')                       // Print String W in actual line
                {
                  if ((l6>0) && (l6<6)) sk=l6;
                  SendCommandLineToScreen();
                  sk=2;
                  if ((yc>10)&&(l6>2)) ClearDisplayAndResetControlVariables(); else if (yc>11) ClearDisplayAndResetControlVariables();       // Reset Screen when line 12 is reached
                }

                if (e2=='S')           // add String W to file xxx4, if arg is even, string T will we added to file, otherwise its overwritten
                {
                  if ((l6<10) ||  (l6>99)) l6=4;
                  hf4=1-l6+(l6/2)*2;
                  ConcatPathWithFileAndNumber(l6);
                  strcpy(h4,h5);
                  WriteToFile(hf4);
                  h3[0]='\0';
                }
              }
            }

            if (e3=='D')
            {

              if ( (e4=='S') && (e2=='C') ) ClearDisplayAndResetControlVariables();             // Delete SCreen Content (Clear)

              if ( (e4=='P') && (e2=='X') )
OneColor(2*c3[16],2*c3[17]+y4,2*c3[18],2*c3[19]+y4,l6/256,l6-l6/256);// Draw pixel bLock (x1=CQ, y1=CR, x2=CS, y1=CT, Color=argument)

              if ( (e4=='L') && (e2=='Y') ) delay(l6);            // DeLaY-option in ms

              if (e2=='P')
              {

                if  (e4=='O') pinMode(hf4, OUTPUT); // controls input Pin=Argument

                if ( e4=='I') pinMode(hf4, INPUT);

                if ( e4=='H') digitalWrite(hf4, HIGH);

                if ( e4=='L') digitalWrite(hf4, LOW);
              }

              if (e2=='R') v3[l4]=digitalRead(hf4); // Digital read pin 'arg' in v-register

              if (e2=='T')                                      // reads Digital Time since UNO got power; seconds are saved in V-, hours in corresponding C-register 
              {
                 c3[l4]=millis()/3600000;                                    // C-register (0-127 hours)
                 v3[l4]=(millis()-3600000*c3[l4])/1000;                      // V-register (0-3600 seconds) ! 
                 v3[l4+1]=millis()-3600000*c3[l4]-1000*v3[l4];               // V+1-register (0-999 millisecs) ! 
              }
              if (e2=='G')                                  // Get Digital touch coordinates (0-119) x=> c-register, y=>c+1-register
              {
                GetXYfromTouchcreen();
                if (ly > 11)
                {
                  c3[l5]=120-lx/2; // C-register
                  c3[l5+1]=ly/2-6; // C+1-register
                }
              }
            }

            if (e3=='V')
            {
              if (e2=='L') v3[l4]=l3-2;      // Save present line in v-register 

              if (e2=='=') v3[l4]=l6;        // Self explaining variable operations...

              if (e2=='+') v3[l4]=v3[l4]+l6;

              if (e2=='-') v3[l4]=v3[l4]-l6;

              if (e2=='*') v3[l4]=v3[l4]*l6;

              if (e2=='/') v3[l4]=v3[l4]/l6;
            }

            if (e3=='C')
            {
              if (e2=='=') c3[l5]=l6;

              if (e2=='+') c3[l5]=c3[l5]+l6;

              if (e2=='-') c3[l5]=c3[l5]-l6;

              if (e2=='*') c3[l5]=c3[l5]*l6;

              if (e2=='/') c3[l5]=c3[l5]/l6;
            }

            if (e3=='A')
            {
              if (e2=='=') a3[c3[l5]]=l6;

              if (e2=='+') a3[c3[l5]]=a3[c3[l5]]+l6;

              if (e2=='-') a3[c3[l5]]=a3[c3[l5]]-l6;

              if (e2=='*') a3[c3[l5]]=a3[c3[l5]]*l6;

              if (e2=='/') a3[c3[l5]]=a3[c3[l5]]/l6;
            }

            if ((e3=='G') && (e4=='T') && (e2=='O') ) l3=l6;      // GoTO line in argument (or recalled register!)

            if ((e3=='G') && (e4=='S') && (e2=='B') )             // GoSuB line in argument (or recalled register!)
            {
              if (gc>9) {strcat(h3,em);strcpy(h4,"END");}
              else
              {
                g3[gc]=l3;
                gc++;
                l3=l6;
              }
            }

            if ((e3=='R') && (e4=='T') && (e2=='N') )      // ReTurN from subroutine
            {
              gc--; if (gc<0) {strcat(h3,":RTE ");strcpy(h4,"END");} else l3=g3[gc];
            }

            if ((e3=='I') &&  ((e2=='>') || (e2=='=') || (e2=='<')))    // If Vx branch to next GTO-line, else skip next line
              if ( !( ((e2=='>') && (v3[l4]>l6)) || ( (e2=='=')&& (v3[l4]==l6) ) || ((e2=='<') && (v3[l4]<l6)) ) ) l3=l3+2;

            if ((e3=='E') && (e4=='N') && (e2=='D') ) ei='X';  // finish execution

            GetXYfromTouchcreen();          // check if F2 is tapped
            if ((ly>308))
            {
              if (lx<30) ei='X';
            }

            if (strlen(h5)+strlen(h3)<29) strcat(h5,h3); // really add input to string W if space is available

          }
          strcpy(h4,h5);                             // print 'end' message if available
          strcpy(h6," ");
          ActivityBar(1);
//          h6[0]='\0';
          h5[0]='\0';
          nm[0]='\0';
          x3=0;
          hc=0;
//          ly=0;
        }

        if ( (ei=='I')  && ((e2=='P') || (e2=='T')) && (strlen(dt)>0) )
        {
          pinMode(DOUT,OUTPUT);
          strcpy(h6,pat);
          strcat(h6,dt);
          if (SD.exists(h6))
          {
            l5=0;
            if ( e2=='T') {l5=atoi(h4);ClearDisplayAndResetControlVariables();}
            l3=0;
            while (l3<9)
            {
              ActivityBar(0);
              strcpy(h6,pat);
              strcat(h6,dt);
              ReadFromFile();
              l3++;

              if ((h4[0]>48) && (h4[0]<58)&& (e2=='P') && (strlen(h4)>5))
              {
                l3=0;
                h3[0]=h4[0];
                h3[1]=h4[1];
                h3[2]=h4[2];
                h3[3]='\0';
                for (l2=4;l2<strlen(h4);l2++) h4[l2-4]=h4[l2];
                h4[l2-4]='\0';
                l2=atoi(h3);
                ConcatPathWithFileAndNumber(l2);
                WriteToFile(0);
              }

//              if ((e2=='T') && (strlen(h4)>0))
              if ((e2=='T') && (h4[0]>31)&& (h4[0]<127))
              {
                l3=0;
                if (strlen(h4)>15)
                {
                  l6=l6-strlen(h4)+15;
                  if (strlen(h4)<29) l6--;
                  h4[15]='\0';
                }
                strcpy(h5,h4);
                SendCommandLineToScreen();
                if (yc>9) l3=9;
              }

              l5=l6;
            }
          }
          l8=0;
          if (e2=='T') {itoa(l6,nm,10);l2=l6;l8=1;strcpy(h6,"-char#");}
          else {strcpy(h6,"-line#");ShowStatus();}
          itoa(l2,h4,10);
          ActivityBar(1);
          strcpy(h5,"");
          hc=0;
          pinMode(DOUT,INPUT);
        }

        if ( ((ei=='X') || (ei=='L'))  && (e2=='P')  && (strlen(dt)>0) )
        {
          pinMode(DOUT,OUTPUT);
          l2=atoi(h4);
              if ( ei=='X')
              {
                strcpy(h4,"CODE:");
                strcpy(h6,pat);
                strcat(h6,dt);
                WriteToFile(0);
                if (e4==0) ei='L';

              }
          if ( ei=='L') ClearDisplayAndResetControlVariables();

          OpenPathAndReadItems();
          if (l2 < 100) l2=100;
          l3=l2;
          l4=0;
          while (l3<999)
          {
            ActivityBar(0);
            ConcatPathWithFileAndNumber(l3);
            strcpy(h5,h3);
            strcat(h5," ");
            if (SD.exists(h6))
            {
              l5=0;
              ReadFromFile();

              if ( ei=='X')
              {
                strcat(h5,h4);
                strcpy(h4,h5);
                strcpy(h6,pat);
                strcat(h6,dt);
                WriteToFile(1);
                if (e4==0) l4++;
              } else

              {
                hc=strlen(h4)+4;
                if (hc>14) {h4[10]='~';h4[11]='\0';hc=15;l4++;}
                strcat(h5,h4);
                SendCommandLineToScreen();
              }
            }
            l3=l3+2;
            if (((yc>9) || (yc+2>fc)) && (ei=='L')) {itoa(l3,nm,10);l3=2000;}
          }
          pinMode(DOUT,INPUT);
          ActivityBar(1);
          hc=0;
          itoa(l4,h4,10);
          strcat(h4," ~S");
          h5[0]='\0';
          h6[0]='\0';
        }

//        'ED'-cmd depreceated for space reasons:
//        if (((ei=='H') || (ei=='E')) && ((e2=='D') || (e2=='A')))
        if ( (ei=='H') && ((e2=='D') || (e2=='A')))
        {
          l5=0;
          if ((strlen(h8)>4)&&(ei=='H')) l5=atoi(h4);
          strcpy(h6,pat);
          strcat(h6,dt);
          if (ei=='E') strcat(h6,h4);
          pinMode(DOUT,OUTPUT);

          if (SD.exists(h6))
          {
            strcpy(h3,h4);
            ReadFromFile();
//        'ED'-cmd depreceated for space reasons (Editing lines with <9 chars is more work than retyping):
/*            if (ei=='E')
            {
              strcpy(h8,">");
              strcat(h8,h3);strcat(h8," ");
              if (strlen(h4)>24) h4[24]='\0';
              strcat(h8,h4);
              strcpy(h4,h8);
            }
*/
            h6[0]='\0';

            if (e2=='A')
            {
             for (l2=0;l2<strlen(h4);l2++)
             {
              if ((h4[l2]>126) || (h4[l2]<32))
              {
                itoa(h4[l2],h3,10);
                if (strlen(h6)+strlen(h3)+strlen(h4)>28) h4[28-strlen(h6)-strlen(h3)]='\0';
                strcat(h6,h3);
                strcat(h6,":");
              }
             }
            }
          } else {strcpy(h6,em);ei='H';}

          pinMode(DOUT,INPUT);
//          l5=0;
        }

        if ((ei=='F') && (e2=='I'))
        {
          strcpy(h6,pat);
          strcat(h6,dt);
          pinMode(DOUT,OUTPUT);

          root = SD.open(h6);

          if (root)
          {
            l4=root.size();
            root.close();
            itoa(l4,h4,10);
          } else strcpy(h4,em);

          pinMode(DOUT,INPUT);

          strcat(h6,"=");
        }

        if ((ei=='M') && (e2=='D'))
        {
          if ((strlen(h8)<5)||((strlen(h8)>14))) //RT-11 file name format (9 char)
          {
            strcpy(h4,"NAME?");
          } else
          {
            strcpy(h6,pat);
            strcat(h6,h4);
            pinMode(DOUT,OUTPUT);
            if (SD.mkdir(h6))
            {
              strcpy(pat,h6);
              strcat(pat,"/");
              ShowStatus();
              strcpy(h4,"OK");
            }
            else strcpy(h4,em);
            pinMode(DOUT,INPUT);
          }
          h6[0]='\0';
        }

        if ((ei=='O') && (e2=='P'))
        {
          if ((strlen(h8)<5)||((strlen(h8)>14)))  //RT-11 file name format (6.3)
          {
            dt[0]='\0';
            ShowStatus();
            strcpy(h4,"NAME?");
          } else
          {
            strcpy(h6,pat);
            strcat(h6,h4);
            pinMode(DOUT,OUTPUT);
            if (SD.exists(h6))
            {
              dt[0]='\0';
              strcat(dt,h4);
              ShowStatus();
              strcpy(h4,"OK");
            } else
            {
              strcpy(dt,h4);
              strcpy(h4,dt);
              WriteToFile(0);
              if (e4==1)
              {
                ShowStatus();
                strcpy(h4,"NEW");
                itoa(100,nm,10);
                e2=124;

              } else strcpy(h4,em);
            }
            pinMode(DOUT,INPUT);
          }
          h6[0]='\0';
        }

        if ((ei=='R') && (e2=='M'))
        {
          strcpy(h6,pat);
          pinMode(DOUT,OUTPUT);

          if (strlen(dt)>0)
          {
            strcat(h6,dt);
            SD.remove(h6);
          } else if (strlen(h6)>1) SD.rmdir(h6);

          if (SD.exists(h6)) strcpy(h4,em);
          else
          {
            if (strlen(dt)>0) dt[0]='\0'; else strcpy(pat,"/");
            ShowStatus();
            strcpy(h4,"OK");
          }
          pinMode(DOUT,INPUT);
          h6[0]='\0';
        }

        if ((ei=='L') && (e2=='S'))
        {
            l5=0;
            if (strlen(h4)>0) l5=atoi(h4);
            ShowStatus();
        }

        if ((ei=='S') && (e2=='B'))
        {
            actBar=1-actBar;
            itoa(actBar,h4,10);
        }

        if ((ei=='C') && (e2=='D'))
        {
            l5=0;
            if (strlen(h4)<1) {strcpy(pat,"/");ShowStatus();}
            else
            {
              strcpy(h6,"/");
              strcat(h6,h4);
              strcat(h6,"/");
              pinMode(DOUT,OUTPUT);
              if (SD.exists(h6))
              {
                strcpy(pat,h6);
                strcpy(h6,":");
                ShowStatus();
              }
              else strcpy(h6,em);
              pinMode(DOUT,INPUT);
            }
        }

        strcat(h6,h4);
//        depreceated for space reasons:
//        if (ei!='E') strcat(h6,"}");
//        if ((hc+strlen(h6)>14)|| (ei=='E'))
        strcat(h6,"}");
        if (hc+strlen(h6)>14)
        {
          strcat(h5,"}");
          SaveCommandLineInBuffer();
          PrintAsciis(y4+yc*10*sk);
          yc++;
          if (yc>11) {ClearDisplayAndPrintBuffer();}
          z3=0;
          x3=0;
          strcpy(h5,h6);

          if (strlen(h5)>15)
          {
            h5[15]='\0';
            PrintLineToDisplayAndBuffer();

            z3=0;
            x3=0;

            h5[0]='\0';
            for (l2=15;l2<strlen(h6);l2++) h5[l2-15]=h6[l2];
            h5[l2-15]='\0';
          }

        } else
        {
          z3=strlen(h5);
//          if (strlen(h6)+strlen(nm)<1) strcat(h5,"?"); else strcat(h5,":");
          strcat(h5,":");
          strcat(h5,h6);
        }
//        depreceated for space reasons (EDIT is not really needed for lines <9 chars):
//        if (ei!='E')        
//        {
        PrintLineToDisplayAndBuffer();
        ResetInputControl();
/*        }     depreceated for space reasons (EDIT is not really needed for lines <9 chars):
        else
        {
          hc=strlen(h5);
          z5=hc;
          PrintAsciis(y4+yc*10*sk);
          lineFeedFlag=0;
          if (strlen(h6)>15) lineFeedFlag=1;
          strcpy (h8, h6);
        }
*/
      }

      if ((ly>280) && (ly<306))
      {
        if ((hc < 2)&&(lineFeedFlag==0)) errOcu=6;
        else
        {
          staOcu=0;
          ConCur();
          if ((lineFeedFlag>0)&&(hc<1))
          {
            z3=15;
            z5=15;
            hc=15;
            x3=240;
            y3=y3-10*sk;
            y2=y3;
            yc--;
            lineFeedFlag--;

            for (l2=0;l2<15;l2++) h5[l2]=ts[15*tc+l2];
            tc--;
            if (tc<0) tc=5;
          }
          z3--;
          z5--;
          hc--;
          h5[hc]='\0';
          h8[hc+lineFeedFlag*15]='\0';
          x3=x3-8*sk;
          x2=x3;
          f1=0x00;
          f2=0x00;
          digitalWrite(LCD_CS,LOW);
          PaiRec(0,0,8,9);
          digitalWrite(LCD_CS,HIGH);
          f1=0xFF;
          f2=0xFF;
        }
      }
    }
    else
    {
     if (strlen(h8)<29)
     {
      if ((ly>250) && (ly<269)) ei=shiftFlag+32+(240-lx)/16; // read keyboard
      if ((ly>268) && (ly<291)) ei=shiftFlag+43+(240-lx)/16;
      if ((ly>290)) ei=shiftFlag+54+(240-lx)/16;
      if (ei==32) ei=126;                              // optimize position of some keys
      if (ei==96) ei=32;
      if (ei==47) ei=96;
      if (ei==97) ei=47;

      h5[hc]=ei;
      h8[hc+15*lineFeedFlag]=ei;
      hc++;
      z5++;
      h5[hc]='\0';
      h8[hc+15*lineFeedFlag]='\0';
     } else errOcu=6;
    }

    if (yc>11)
    {
      ClearDisplayAndPrintBuffer();
      ResetInputControl();
      x2=0;
    }
    staOcu=0;
    ConCur();

    f1=0xFF;
    f2=0xFF;
    PrintAsciis(y4+yc*10*sk);
    if (hc>14)
    {
      SaveCommandLineInBuffer();
      yc++;
      lineFeedFlag++;
      if (yc>11) ClearDisplayAndPrintBuffer();
      z5=0;
      hc=0;
      z3=0;
      x3=0;
      x2=0;
      h5[0]='\0';
    }
    delay (190);
    ly=0;
  }
  couOcI++;
  if (couOcI>9) // cursor blink multiplier
  {
    couOcI=0;
    ConCur();
  }
  delay (60); // minimal cursor blink freq, space for slice management
}