H4EAM

          C-Aabits (vigadega):
          https://et.wikibooks.org/wiki/C_algajatele

C-keel arduino huvilistele
--------------------------

Eelneval aastatuhandel (siis, kui aastanumber algas ühega, vaata "Viikingiaeg"[1]) algas nn. Uniksiaeg[2] (01.01.1970), mida peetakse ka C-keele sünniaastaks. Ilusa väikse iidse keele eelisteks siiamaani jäävad kiirus ja maht. See tähendab, et algtekstist kiiresti saab kahendkoodi, mis jääb ainult ~20% alla otse masinakoodides kirjutatud programmile (kiiruse suhtes).

Kaheksakümnendatel sündis C++, mis võrreldes C-ga võis olla nii inimsõbralikum kui ka inimvaenulikum (sõltuvalt programmeerija tahtest), kuid tulemuseks oli suurema mahuga ja aeglasem binaarkood.

Harjutsus: Kirjutage "Tere maailm!" programmi C ja C++-ga enda operatsioonsüsteemi konsooli jaoks, mõõtke ehitatud binaarkoodi mahtu ning tööaega.

Ca. 2006 aastal sündis idee kirjutada C++'is sellist programmi, mida enimjuhtudel poleks vaja puudutada ning ainult lisada koodi juurde. Programm oli mõeldud Atmel AVR kontrollerite programmeerimiseks. Algaja ei pidanud enam alustama pead ringi panevast hüppest, mis peale maandumist tegi hüpet mõtetuks, kuna hüppe tulemusena temast koheselt saab mittealgaja. Idee autor aga ei pidanud C kompilaatorit muutma hakkama (see mõte läks Microsoft'ile maksma astronoomilise summa (aegadel, millal nad proovisid "event processing macro" MSVC keele osaks teha (~1995))). Samas alustati tootma Arduino arvuteid ja lisamooduleid nende jaoks -- nii et tehtud C++ "parandus" ei mõjutanud olemasolevaid turge.

Kirjutades Arduino dialektis, meile pakutakse mugavamat viisi taimeri, analoogsisendite, PWM (pulse width modulation), järjestikporti, LCD ekraani ja paljude teiste perifeeriaseadmete programmeerimiseks (võrreldes näiteks AVR C-ga, kus ülesannet lihtsamaks teeb "interneti seenelkäik" -- vabavara litsensiga valmislahenduste otsingud. Aastatega neid tuleb küll juurde, kuid kõik see võtab tublisti aega).

Kui Arduino ostmist pole veel otsustatud (~2EUR Hiinas), võib harjutada simulaatoritel või näiteks mängida meie uduino.h ("unix duino") headeriga.

Ostes väikest Arduino-Uno plaati, märkasin ma, et kuigi tal on kõik täisarvuti omadused olemas (16 MHz 8-bitine protsessor, 2K mälu, 20 baiti säilmälu (muutmälu, milles andmed säilivad ka pärast toite väljalülitamist), kuid puuduvad ekraan ja klaviatuur. Üks mõte oleks kasutada järjestiku porti (läbi USB), teine aga ehitada tulnuka klaviatuuri ("0","1","Enter"), ning juurde osta LCD16x2 ekraani. Esimine mõte meeldis paremini.

Arduinoga suhtlemiseks kasutame mõnda terminal-programmi, näiteks PuTTY't.

Lihtne "Echo" programm testimiseks.

echo.ino

  void setup()
  {
      Serial.begin( 9600);
      while ( !Serial);
  }

  void loop()
  {
      if ( Serial.available() > 0) {
          int inByte = Serial.read();
          PORTC = (unsigned char)inByte;
          char s[] = " \r\n";
          s[0] = (unsigned char)inByte;
          Serial.write( s);
      }
  }

Ehitame uduino.h
----------------

Alustame koodist, mis paistab läbi UnoArduSim simulaatoris [Adopt]:

  int main() {
      setup();
      while ( true) {
          loop();
      }
  }

"SoFar" variant areneb "cache" põhimõtte alusel -- kirjutame juurde seda, mida hetkel vajame, ning pärast ei kustuta maha. Piisab ühest päevast, et näha et valitud tee polegi valmis ehitatud -- võib olla et kunagi oli, kuid jõudis juba laguneda.

Teise sammuna oleks vaja Arduino String klassi. GCC-ga levitav standartne std::string ei oma just seda (konstruktoreid), mida meile on kõige esimesena vaja --:

  String( char);                 String( long);
  String( unsigned char);        String( unsigned long);
  String( short);                String( long long);
  String( unsigned short);       String( unsigned long long);
  String( int);                  String( float);
  String( unsigned int);         String( double);

Otse Arduino'st võetud failid WString.h ja WString.cpp viitavad aga hoopiski antiik funktsioonidele, nagu itoa, utoa, ltoa, ultoa, ecvt, fcvt. Nende algkoode ei leia enam nii lihtsalt, kuna nad ei pidanud olema standartsed, jäljed AVR libc algkoodides viivad meid aga assembleris kodeeritud failide juurde.

Kahaneva C-keele populaarsuse lainel (aastaga 20-lt 6 protsendile, TIOBE) mõtlesin: esimene raketi aste tegi oma tööd. Olgu Python, C#, Swift, Ruby sama edukad järgmise 40 aasta jooksul. Kui vaja, taastame C kiiresti ja kvaliteetselt. Paistab et ei, jälle läheb vaja midagi 10000 aastat:)

Mingisugused killud on veel net-is nähtavad, hakkan nendest kollektsiooni koguma:

  avr-libc-1.8.1\include\stdlib.h

  char *itoa(int val, char *s, int radix);
  char *utoa(unsigned int val, char *s, int radix);
  char *ltoa(long val, char *s, int radix);
  char *ultoa(unsigned long val, char *s, int radix);
  char *dtostrf(double __val, signed char __width,
                unsigned char __prec, char *__s);

"Sofar" koodi kasutamine:
-------------------------

uduino.h

  #include <iostream>
  #include <string>
  #include <unistd.h>
  #include <sys/time.h>

  unsigned long long start_time = 0;

  class USerial {
      public:
          void begin( int aspeed) {};
          void write( std::string astr) {
              std::cout << astr << std::endl;
          }
  };

  USerial Serial;

  void setup();
  void loop();
  unsigned long long msSinceEpoch();
  unsigned long millis();
  void delay( int);

  unsigned long long msSinceEpoch() {
      struct timeval tv;
      gettimeofday(&tv, NULL);
      unsigned long long vms =
          (unsigned long long)(tv.tv_sec) * 1000 +
          (unsigned long long)(tv.tv_usec) / 1000;

      return( vms);
  }

  unsigned long millis() {
      msSinceEpoch() - start_time;
  }

  void delay( int ams) {
      usleep( ams * 1000);
  }

  int main() {
      start_time = msSinceEpoch();
      setup();
      while ( true) {
          loop();
      }
  }

test.cpp

  // linux compile: g++ test.cpp -o test

  #include "uduino.h"

  void setup() {
      Serial.begin( 9600);
      Serial.write("in setup now\n");
  }

  void loop() {
      printf("looping for a while %lu\n", millis());
      delay( 1000);
  }

Viited
------

[1]. Viikingiaeg

  https://et.wikipedia.org/wiki/Viikingiaeg

[2]. Unix time

  https://en.wikipedia.org/wiki/Unix_time

[3]. How can i get UTCTime in milliseconds

    http://stackoverflow.com/questions/1952290
        /how-can-i-get-utctime-in-millisecond-
        since-january-1-1970-in-c-language

[4]. Arduino String constructor

    https://www.arduino.cc/en/Reference/StringConstructor

[5]. CDROM on DOS computer

    http://manmrk.net/tutorials/DOS/cdrom.htm

[6]. "String" in TURBO C++

    http://jaspreetscodezone.blogspot.com.ee
          /2008/03/string-in-turbo-c.html

[7]. Simple C++ String Class

    http://www.neoegm.com/tech/programming/c-cpp/simple-string-class/

[8]. http://www.geeksforgeeks.org/implement-itoa/

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Garbage

#include <iostream>

using namespace std;

class Foo {
  public:
    Foo() { cout << "default constructor" << endl; }
    ~Foo() { cout << "default destructor" << endl; }
};

int main() {
  Foo F;
}

virtu@GBOX:~/C$ g++ WString.cpp 2>&1 | grep "was not declared in this"

WString.cpp:72:23: error: ‘utoa’ was not declared in this scope
WString.cpp:80:23: error: ‘itoa’ was not declared in this scope
WString.cpp:96:23: error: ‘ltoa’ was not declared in this scope
WString.cpp:104:24: error: ‘ultoa’ was not declared in this scope
WString.cpp:112:64: error: ‘dtostrf’ was not declared in this scope

WString.cpp:188:20: error: ‘PGM_P’ was not declared in this scope
WString.cpp:248:43: error: ‘strlen_P’ was not declared in this scope
WString.cpp:344:43: error: ‘strcpy_P’ was not declared in this scope

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

discovering Kaleka code (http://jaspreetscodezone.blogspot.com.ee)

  $ cat testbool.cpp
  #include <iostream>

  using namespace std;

  union U {
      bool a;
      unsigned char x;
  };

  int main() {
      cout << sizeof( bool) << endl;
      U u; u.a = false;
      cout << (int)u.x << endl;
      u.a = true;
      cout << (int)u.x << endl;
      return 0;
  }
  $ g++ testbool.cpp -o testbool
  $ ./testbool
  1
  0
  1

Conclusion: j_bool.h errors come from using words, that became reserved later.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/*
   A C++ program to implement itoa()
   http://www.geeksforgeeks.org/implement-itoa/
 */

#include <iostream>
using namespace std;

/* A utility function to reverse a string  */
void reverse(char str[], int length)
{
    int start = 0;
    int end = length -1;
    while (start < end)
    {
        swap(*(str+start), *(str+end));
        start++;
        end--;
    }
}

// Implementation of itoa()

char* itoa(int num, char* str, int base)
{
    int i = 0;
    bool isNegative = false;

    /* Handle 0 explicitely, otherwise empty string is printed for 0 */
    if (num == 0)
    {
        str[i++] = '0';
        str[i] = '\0';
        return str;
    }

    // In standard itoa(), negative numbers are handled only with
    // base 10. Otherwise numbers are considered unsigned.
    if (num < 0 && base == 10)
    {
        isNegative = true;
        num = -num;
    }

    // Process individual digits
    while (num != 0)
    {
        int rem = num % base;
        str[i++] = (rem > 9)? (rem-10) + 'a' : rem + '0';
        num = num/base;
    }

    // If number is negative, append '-'
    if (isNegative)
        str[i++] = '-';

    str[i] = '\0'; // Append string terminator

    // Reverse the string
    reverse(str, i);

    return str;
}

// Driver program to test implementation of itoa()
int main()
{
    char str[100];
    cout << "Base:10 " << itoa(1567, str, 10) << endl;
    cout << "Base:10 " << itoa(-1567, str, 10) << endl;
    cout << "Base:2 " << itoa(1567, str, 2) << endl;
    cout << "Base:8 " << itoa(1567, str, 8) << endl;
    cout << "Base:16 " << itoa(1567, str, 16) << endl;
    return 0;
}

