Järjestelmän ulkoinen kuvaus

v1.0
27.11.95

Järjestelmä on jaettu neljän osasysteemiin. Nämä ovat 1. prosessori, 2. anturit ja toimilaitteet, 3. käyttöliittymä ja 4. fysiikkamalli.
Osien välisistä riippuvuuksista on suunniteltu malli DFD-muodossa.
Simulaattori toteutetaan pääasiallisesti C++:lla, mahdollisesti osittain C:llä. Säikeitä ei käytetä vaan kontrolli siirtyy yksinkertaisilla funktionkutsuilla. Käyttöliittymä ohjaa kaikkia muita osia kutsumalla tarvittavia luokkien julkisia jäsenfunktioita.

Järjestelmän kontrollin siirtyminen on kuvattu Use Case Map notaatiota käyttäen. Use Case Map on korkean tason kuvausmenetelmä, josta voi lukea lisää pian ilmestyvästä kirjasta A Use Case Map Approach to High-Level Design of Object Oriented Systems, R.J.A. Buhr, R.S. Casselman.

Prosessori

Prosessorin tehtävänä on simuloida 68HC11A1:stä, uBoard-piirikortilla olevia ulkoista muistia ja EPROM:ia sekä uBoard- kortin ja muun laitteiston rajapintaa. Koko järjestelmä käyttää prosessorilta saatavaa aikaa. Prosessoriin toteutetaan myös debuggauskäyttöliittymä. Käyttöliittymä käskee prosessoria suorittamaan yhden käskyn kerrallaan kutsumalla funktiota Suorita_kasky. Kun simulointi on pysähdyksissä käyttöliittymä voi muuttaa lokiintulostusta tai pysähtymisehtoja funktioilla lokitulostustiedot, aseta_rekisteri_breakpointit tai aseta_breakpointit. Samoin se voi laittaa päälle tai ottaa pois päältä lokiintulostus ja breakpoint toiminnot funktioilla lokitulostukset ja breakpointit. Mahdollinen lokiin tulostus ja breakpointien tarkkailu on siis prosessori-osajärjestelmän tehtävä. Lokitulostukset tehdään tekstitiedostoon. Jos breakpoint saavutetaan prosessori välittää siitä tiedon käyttöliittymälle, joka pysäyttää simuloinnin olemalla kutsumatta enää prosessorin suorita_kasky funktiota (ennen kuin käyttäjä mahdollisesti ilmoittaa taas haluavansa jatkaa). Simuloinnin ollessa pysähdyksissä käyttöliittymästä voi myös muuttaa rekistereiden arvoja kutsumalla funktioita Aseta_a, Aseta_b, Aseta_d, Aseta_x, Aseta_y, Aseta_sp ja Aseta_pc.
Prosessori 'lataa' suoritettavan kooditiedoston saatuaan käyttöliittymältä tiedoston nimen ja kehotuksen lataamiseen funktiolla Lataa_koodi. Kooditiedosto on S19-formaattiin käännetty tiedosto.
Prosessori kommunikoi anturit ja toimilaitteet osajärjestelmän kanssa ainoastaan lukemalla ja kirjoittamalla liitäntärimaan ja kutsumalla jokaisen käskyn suorituksen jälkeen antureille ja toimilaitteille kuuluvaa funktiota, keraa_tiedot, joka välittää sille ajan ja kehottaa sitä tarkastamaan riman arvot.

Seuraavassa kaikki funktiot joita on tarkoitus kutsua prosessori-osasysteemin ulkopuolelta. Anturit ja toimilaitteet -osasysteemi kutsuu ainoastaan Liitäntäriman funktioita, kaikki muut funktiot on tarkoitettu käyttöliittymä-osasysteemin kutsumiksi.

typedef unsigned char byte; // tavu 8 bittiä
typedef long word; // sana 16 bittiä

class CPU
{
public:

// Konstruktori

CPU();

// Staattinen osoitefunktio, jolta luokan palvelujen käyttäjät voivat kysyä viimeksi luodun instanssin
// osoitetta. Jos viimeisen luonnin jälkeen jokin luokan instanssi on tuhottu, palautetaan NULL.

static CPU *Osoite ();

// Funktiot rekisterien arvojen muuttamista varten

void Aseta_a(byte arvo);
void Aseta_b(byte arvo);
void Aseta_d(word arvo);
void Aseta_x(word arvo);
void Aseta_y(word arvo);
void Aseta_sp(word arvo);
void Aseta_pc(word arvo);

// Destruktori

~CPU();

}; // CPU

class ohjaus
{
public:

/* Prosessori suorittaa yhden käskyn.
Palauttaa prosessorin pysähtymisen syyn.
0 = ei ole pysähtynyt
1 = breakpoint
2 = tuntematon käsky
Jos pysähtymisen syy oli breakpoint, palauttaa argumenttina kyseisen
breakpointin. Argumenttina palautetaan lisäksi kulunut aika sekunteina. */

int suorita_kasky(char *breakpoint, double *aika);

/* Kysytään rekisterien ja muistin sisältö.
Palauttaa argumenteissa rekisterit ja osoittimet muistien alkuun.
Muisti on merkkitaulukko. */

void rekisterit_ja_muisti(char *a, char *b, short *d, short *pc, short *sp, short *x, short *y, char *cc, char *sis_muisti, char *ulk_muisti);

/* Annetaan ehdot, joilla prosessori pysähtyy.
Palauttaa, oliko ehtolauseke laillinen vai ei.
0 = oikein
1 = virheellinen
Ehdot on merkkitaulukko. */

bool aseta_rekisteri_breakpointit(char *ehdot);

bool aseta_breakpointit(int suoritettuja_kaskyja, short data_alku, short data_loppu);

/* Annetaan tiedot, jotka tulostetaan lokiin.

void lokitulostustiedot(short muistin_alku, short muistin_loppu,
bool rekisterit, bool luku/kirj);

/* Asetetaan breakpointit päälle tai pois.
tila = 1: päälle
tila = 0: pois */

void breakpointit(bool tila);

/* Asetetaan lokitulostukset päälle tai pois.
tila = 1: päälle
tila = 0: pois */

void lokitulostukset(bool tila);

}; // ohjaus

class IO-laitteet
{
public:

// Konstruktori

IO-laitteet();

// Staattinen osoitefunktio, jolta luokan palvelujen käyttäjät voivat kysyä viimeksi luodun instanssin
// osoitetta. Jos viimeisen luonnin jälkeen jokin luokan instanssi on tuhottu, palautetaan NULL.

static IO-laitteet *Osoite();

// Ladataan suoritettava tiedosto EEPROMiin.
// Palauttaa, onnistuiko tiedoston avaaminen.
// TRUE = onnistui
// FALSE = ei onnistunut

bool Lataa_koodi(char *tiedostonnimi);

// Destruktori

~IO-laitteet();

}; // IO-laitteet

class Liitantarima
{
public:

// Konstruktori

Liitantarima();

// Riman kautta kulkevat tiedot mikrokontrollerin ja auton välillä
// Rimassa on 64 nastaa

// Staattinen osoitefunktio, jolta luokan palvelujen käyttäjät voivat kysyä viimeksi luodun instanssin
//osoitetta. Jos viimeisen luonnin jälkeen jokin luokan instanssi on tuhottu, palautetaan NULL.

static Liitantarima *Osoite ();

// Haetaan tietoa rimasta. Argumenttina annetaan nastan numero (1-64).
// Palauttaa jännitteen voltteina.

double Hae(int nasta);

// Päivitetään liitäntäriman sisältöä. Argumenttina annetaan nastan
// numero (1-64) ja sen jännite.

void Paivita(int nasta, double jannite);

// Destruktori

~Liitantarima();

}; // Liitantarima

Käyttöliittymä

Käyttöliittymä (rata ikkunaa ei näy kuvassa) huolehtii ohjelman kontrollista kutsumalla prosessorisimulaattoria ja fysiikkamallia, nämä rajapinnat on määritelty prosessorin ja fysiikkamallin rajapinnoissa.

Auton tila esitetään kahdessa eri ikkunassa. Toisessa auton sijainti radalla ja toisessa auton parametrit (voimat, suunta, nopeus jne.) Renkaista lähtevät voimat ovat autoon vaikuttavia kitkavoimia. Rengaskulma esitetään eturenkaiden kääntymisellä, samoin kuin ohjauksen kohdekulma (katkoviivalla piirretyt eturenkaat). Moottorin teho visualisoidaan auton rungossa olevalla palkilla, josta näkee kuinka monta prosenttia moottorin tehosta yritetään saada. Anturit ovat värillisiä ympyröitä, joiden sävyt vaihtelevat antureiden kirkkauden mukaan. Nopeusvektori lähtee auton rungon keskipisteestä. Auto myös pyörii keskipisteensä suhteen, riippuen missä suunnassa auto on. Muut arvot, eli kulmanopeus, rengasnopeus ja aika ovat skalaareja ja nämä näytetään numeroarvoina.

Rata näytetään kaksiuloitteisena ja auto liikkuu tätä rataa pitkin.

Muisti esitetään taulukossa heksadesimaalilukuina. Muisti-ikkunoita voi avata tarpeen vaatiessa lisää napista new ja siten voi seurata niitä muistiosoitteita, joista on kiinnostunut. Sisäiselle ja ulkoiselle muistille on omat ikkunansa.

Fysiikkamalli

Fysiikkamallin tehtävänä on simuloida annettujen ohjaussignaalien mukaisesti auton liikettä radalla ja tuottaa auton liikkeen ja sijainnin perusteella tarvittavat tiedot antureille, sekä välittää näytölle tarvittavat tiedot auton kulun havainnollistamiseksi.

Fysiikkamalliin yhteydessä olevat ohjelmiston osat ovat toimilaitelohko, käyttöliittymä ja ratatiedosto. Fysiikkamalli lukee radan tiedot rataoliolta, kun simulointi alkaa. Tasaisin väliajoin (luokkaa tuhansia kertoja sekunnissa kuvattavan mallin aikaa) käyttöliittymä välittää fysiikkamallille tiedon kuluneesta ajasta. Aikaväli ei ole täysin vakio, vaan riippuu edellisen prosessorin suorittaman käskyn pituudesta. Fysiikkamalli kysyy auton saamat ohjaussignaalit (renkaiden kulma ja moottorin teho) toimilaiteosalta.

Fysiikkamalli määrittelee auton tilan kyseisen ajan kuluttua ja antaa käyttöliittymälle (näytölle) tiedon auton tilasta (sijainti, asento, nopeus, kulmanopeus, rengasnopeus ja voimavektorit) sekä antureiden tarvitsemat tiedot (ledien etäisyydet teipistä ja rengasnopeus) toimilaitelohkolle. Tiedot välitettyään fysiikkamalli jää odottamaan seuraavaa yhteydenottoa.

Seuraavassa fysiikkaosan luokat ja julkiset jäsenfunktiot eli funktiot, joita voidaan kutsua sen ulkopuolelta.

// Fysiikkamalli

// Auto on fysiikkamallin keskeinen luokka, jonka tilan muutoksista
// muut ovat kiinnostuneita.

class FmAuto
{
public:

  // Konstruktori, jota käyttöliittymä kutsuu simuloinnin alkaessa.
  // Parametrit ilmoittavat auton paikan ja asennon rataolion 
  // ilmoittamalla radalla.

  FmAuto (int alkupiste_x, int alkupiste_y, double alkuasento);


  // Destruktori, joka nollaa staattisen yksityisen muuttujan id.
  // Toteutettu inline-funktiona header-tiedoston lopussa.

  ~FmAuto ();


  // Staattinen osoitefunktio, jolta luokan palvelujen käyttäjät voivat 
  // kysyä viimeksi luodun instanssin osoitetta. Jos viimeisen luonnin
  // jälkeen jokin luokan instanssi on tuhottu, palautetaan NULL.

  static FmAuto *Osoite ();


  // Käyttöliittymä käskee fysiikkamallia liikahtamaan tietyn ajan
  // eteenpäin. Aika on edellisestä kutsusta kulunut auton maailman aika.
  // Paluuarvonaan funktio palauttaa tiedon, onko auto radan päällä.
  // Lisäksi funktio palauttaa näytön haluamia tietoja muuttamalla
  // funktioparametreja. Paikka on auton sijainti rataolion ilmoittamassa
  // koordinaatistossa. Asento on auton kulma myötäpäivään positiiviseen 
  // y-akseliin nähden, [-pii..pii].

  bool Auton_sijainti (double aika,
		       int *paikkax, 
		       int *paikkay, 
		       double *asento);
  
  // Käyttöliittymä voi kysyä autoon vaikuttavia voimia. Nopeusvektorin
  // kulma on rataan nähden ja voimavektoreiden auton runkoon nähden.

  void Auton_voimat (Vektori *nopeus,
		     double *kulmanopeus,
		     Vektori *kitka_etu,
		     Vektori *kitka_taka,
		     double *rengasnopeus);


  // Nopeusanturi kutsuu rengasnopeus-funktiota. Rengasnopeus tarkoittaa 
  // renkaan alapinnan nopeutta auton alustaan nähden. Paluuarvo m/s.

  double Rengasnopeus ();


  // Fotodiodikampa kutsuu etaisyys teipista -funktiota. Se palauttaa
  // anturin numeron ilmoittaman ledi-fotodiodi -parin määräämän 
  // mittauspisteen pienimmän etäisyyden teipistä metreinä.

  double Etaisyys_teipista (char anturin_numero);

private:

  static FmAuto *id = NULL;

};

inline FmAuto::~FmAuto ()
{
  id = NULL;
}

inline FmAuto
*FmAuto::Osoite ()
{
  return id;
}


// Vektori on fysiikkamallin ja näytön käyttämä luokka.

class Vektori
{
public:

  // Konstruktori

  Vektori ();


  // Summafunktio

  Vektori operator+ (Vektori ensimmainen, Vektori toinen);


  // Komponentit ovat julkisia.
  // Suunta on radiaaneja myötäpäivään, [-pii..pii].

  double suunta;

  double pituus;

};

Toimilaiteosa

Toimilaiteosan tarkoituksena on suodattaa prosessorin tuottamista signaaleista informaatiota fysiikkamallin käyttöön ja fysiikkamallin palautteista signaaleja prosessorille. Samalla toimilaiteosa tuottaa informaatiota myös näytön tarpeisiin.

Toimilaiteosaan yhteydessä olevat ohjelmiston osat ovat prosessori, näyttö ja fysiikkamalli. Toimilaiteosa saa prosessorilta tiedon kuluneesta ajasta ja lukee prosessorin rimaoliolta tiedon toimilaitteille tulevista signaaleista. Toimilaiteosa kerää tiedot ja muokkaa ne fysiikkamallille moottorin tehoksi ja jarruvoimaksi sekä renkaiden asennoksi. Säännöllisin väliajoin fysiikkamalli kysyy tiedot toimilaitteilta. Toimilaitteet kysyvät tarvitessaan fysiikkamallilta rengasnopeutta ja fotodiodien etäisyyksiä ratateipistä. Toimilaiteosa tuottaa prosessorin rimaoliolle signaaleja jatkuvasti, mutta kulmapotentiometriä lukuunottamatta niiden informaatiosisältö voi muuttua vain niin usein kuin fysiikkamallia on kutsuttu. Tämä ei liene ristiriidassa todellisuuden kanssa, sillä auton on ehdittävä liikkua, jotta antureiden annoissa tapahtuisi muutoksia. Kontrollerissa pyörivän ohjausohjelman on todellisuudessakin osattava huomioida vasteen viipyminen.

Seuraavassa toimilaiteosasta ulos näkyvät jäsenfunktiot.

// Toimilaiteosa

// Laitteet on luokka, joka instantioi ja pitää sisällään kaikki 
// toimilaitteet ja anturit. Se toimii näiden rajapintana ulkomaailmaan.

class TlLaitteet
{
public:
  
  // Konstruktori, jota käyttöliittymä kutsuu simuloinnin alkaessa.
  // Asettaa instanssin osoitteen staattiseen yksityiseen muuttujaan id
  // Osoite-funktiota varten.

  // TlLaitteet::TlLaitteet () : id(this)
  //   {
  //     ...
  //   }
  
  TlLaitteet ();


  // Destruktori, joka nollaa staattisen yksityisen muuttujan id.
  // Toteutettu inline-funktiona header-tiedoston lopussa.

  ~TlLaitteet ();


  // Staattinen osoitefunktio, jolta luokan palvelujen käyttäjät voivat 
  // kysyä viimeksi luodun instanssin osoitetta. Jos viimeisen luonnin
  // jälkeen jokin luokan instanssi on tuhottu, palautetaan NULL.
  // Toteutettu inline-funktiona header-tiedoston lopussa.

  static TlLaitteet *Osoite ();


  // Prosessori kutsuu käskyn suoritettuaan.
  // Aika on simuloinnin alusta kulunut auton maailman kokonaisaika.
  // Funktio lukee liitinluokan arvoja ja muuttaa niitä paluuarvonaan.
  
  void Keraa_tiedot (double aika);


  // Näyttö kutsuu saadakseen fotodiodianturin havainnoiman
  // kirkkauden. Anturin_numero on välillä 1 - 6.
  // Paluuarvo välillä [0..1].

  double Heijastunut_kirkkaus (char anturin_numero);


  // Näyttö kutsuu saadakseen moottorin prosentuaalisen tehon,
  // joka moottorista yritetään saada. Paluuarvo välillä [0..100].

  double Tehoprosentti ();

  
  // Auto kutsuu halutessaan moottorin hetkellisen tehon yhteensä
  // molemmille akseleille. Auto itse tietää jakautumissuhteen.
  // Paluuarvo watteina.

  double Moottorin_teho ();


  // Auto kutsuu halutessaan tietää molempien akseleiden yhteisen
  // jarrutusvoiman. Auto itse tietää jakautumissuhteen.
  // Paluuarvo newtoneina.

  double Jarruvoima ();


  // Näyttö kutsuu halutessaan tietää asennon, johon ohjaus on 
  // matkalla. Paluuarvo on eturenkaiden kulma radiaaneissa 
  // myötäpäivään auton runkoon nähden. Arvo on välillä [-pii/2..pii/2].

  double Ohjauksen_kohdekulma ();


  // Näyttö tai fysiikkamalli kutsuu halutessaan renkaiden kulman
  // tietyllä hetkellä. Paluuarvo on eturenkaiden kulma radiaaneissa 
  // myötäpäivään auton runkoon nähden. Arvo on välillä [-pii/2..pii/2].

  double Rengaskulma ();

private:

  static TlLaitteet *id = NULL;

};

inline TlLaitteet::~TlLaitteet ()
{
  id = NULL;
}

inline TlLaitteet 
*TlLaitteet::Osoite ()
{
  return id;
}



Rata

Rata tiedosto sisältää kuvauksen radasta. Tiedoston tarkkaa muotoa ei olla vielä päätetty, mutta sen pitää sisältää vektorikuvauksen rataosista, rataosien mittakaavan ja teipinleveyden. Ratatiedoston parsiminen kuuluu käyttöliittymä-modulin tehtäviin.

Rataolion luokkakuvaus:

// Rata

class Rata
{
public:
   Rata ();
   ~Rata ();

   // VektoriDeque on kahteensuuntaan linkitetty lista luokka,
   // jonka arvot ovat luokan Vektori komponentteja.

   VektoriDeque ratavektorit;

   // Mittakaava metreissä (kuinka monta metriä on yksikkö).

   double mittakaava;

   // Teipinleveys metreissä.

   double teipinleveys;

   // Paluttaa seuraavan ratavektorin.

   Vektori anna_seuraava ();

   // Paluttaa jono-osoittimen sen hetkisen vektorin.

   Vektori anna_tama ();

   // Paluttaa edellisen ratavektorin.

   Vektori anna_edellinen ();

   // Siirtää osoitinta eteenpäin.

   void taaksepain ();

   // Siirtää osoitinta taaksepain.

private:

   // Jonon osoitin.

   Vektori *osoitin;
}