F12E8


    ..И кричит: "Кири-ку-ку. Царствуй, лежа на боку!"

    А.С.Пушкин о микроконтроллерах (Сказка о золотом петушке)

C#: ARM и .NET micro
--------------------

Есть много разных решений на тему микроконтроллеров и .NET.

Это Netduino от Secret Labs [1], .NET Gadgeteer от Microsoft [2], STM32F4Discovery [3], Андроидные решения на базе Xamarin Platform [4], и другие [5]..

На данный момент нас интересуют возможности самой .NET Micro framework [6].

  -- Поддерживаются языки C# и VB. Для C# существует opensource реализация от Novell.

Начнем издалека - С#/Ubuntu. Инсталлировано:

  apt-get install mono-complete libcairo2-dev


Кукбук (Cookbook)
-----------------

В Monodevelop (v.4.0.12):

  View -> Pads -> Application Output
  Project -> Edit References -> Packages: Mono.Cairo [v]

  Mono JIT compiler version 3.2.8 (Debian 3.2.8+dfsg-4ubuntu2)

0. Wizard code

  using System;
  using Gtk;

  namespace GTO
  {
    class MainClass
    {
      public static void Main (string[] args)
      {
        Application.Init ();
        MainWindow win = new MainWindow ();
        win.Show ();
        Application.Run ();
      }
    }
  }

1. Здравствуй, Мир!

  // mcs -pkg:gtk-sharp-2.0 helloword.cs

  using System;
  using Gtk;

  public class GtkHelloWorld {

    public static void Main() {
      Console.WriteLine("Здравствуй, Мир!");
    }
  }

2. GTO

  using System;
  using Gtk;

  namespace GTO {

    public class GtkGTO {

      public static void Main() {
        Application.Init();

        Window w = new Window("GTK");
        w.Resize(200,200);

        Label l = new Label();
        l.Text = "ГТО";
        w.Add( l);

        w.ShowAll();
        Application.Run();
      }
    }
  }

3. Семисегментный Фонт

  using System;
  using Cairo;
  using Gtk;

  public class GtkCairo
  {
    static void Main ()
    {
      Application.Init ();
      Gtk.Window w =
        new Gtk.Window ("Семисегментный Фонт");

      DrawingArea a = new CairoGraphic ();

      Box box = new HBox (true, 0);
      box.Add (a);
      w.Add (box);
      w.Resize (1160, 800);
      w.DeleteEvent += close_window;

      Gdk.Color col = new Gdk.Color();
      Gdk.Color.Parse("black", ref col);
      a.ModifyBg(StateType.Normal, col);

      w.ShowAll ();

      Application.Run ();
    }

    static void close_window (object obj, DeleteEventArgs args)
    {
      Application.Quit ();
    }
  }

  public class CairoGraphic : DrawingArea
  {
    int[] font = new int[] {
      0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07,
      0x7f, 0x6f, 0x77, 0x7c, 0x58, 0x5e, 0x79, 0x71,
      0x3d, 0x74, 0x19, 0x0d, 0x76, 0x38, 0x36, 0x54,
      0x5c, 0x73, 0x67, 0x50, 0x6c, 0x78, 0x3e, 0x1c,
      0x7e, 0x14, 0x6e, 0x49, 0x00, 0x08, 0x40, 0x48
    };

    static void DrawRect(
      Cairo.Context g,
      double x,
      double y,
      double width,
      double height
      )
    {
      g.MoveTo ( x, y);
      g.LineTo ( x + width, y);
      g.LineTo ( x + width, y + height);
      g.LineTo ( x, y + height);
      g.ClosePath ();
    }

    static void Draw7Seg(
      Cairo.Context g,
      int c,
      double x,
      double y
      )
    {
      g.Save ();
      if ((c & 0x01) != 0) DrawRect (g, 30 + x, 10 + y, 50, 20); // xywh
      if ((c & 0x02) != 0) DrawRect (g, 80 + x, 30 + y, 20, 50);
      if ((c & 0x04) != 0) DrawRect (g, 80 + x, 100 + y, 20, 50);
      if ((c & 0x08) != 0) DrawRect (g, 30 + x, 150 + y, 50, 20);
      if ((c & 0x10) != 0) DrawRect (g, 10 + x, 100 + y, 20, 50);
      if ((c & 0x20) != 0) DrawRect (g, 10 + x, 30 + y, 20, 50);
      if ((c & 0x40) != 0) DrawRect (g, 30 + x, 80 + y, 50, 20);
      g.ClosePath ();
      g.Restore ();
    }

    protected override bool OnExposeEvent (Gdk.EventExpose args)  {
      using (Context g = Gdk.CairoHelper.Create (args.Window)){
        for (int x = 0; x < 40; x++)
          Draw7Seg (
            g,
            font [x],
            30 + 110 * (x % 10),
            30 + 180 * (x / 10));
        g.SetSourceRGBA (0, 0.5, 0, 1);
        g.FillPreserve ();
      }
      return true;
    }
  }

4. Hello World (Семисегментный микс, 2015.01.08)

  using System;
  using Cairo;
  using Gtk;

  public class GtkCairo
  {
    static void Main ()
    {
      Application.Init ();
      Gtk.Window w =
        new Gtk.Window ("Семисегментный Фонт");

      DrawingArea a = new CairoGraphic ();

      Box box = new HBox (true, 0);
      box.Add (a);
      w.Add (box);
      w.Resize (600, 400);
      w.DeleteEvent += close_window;

      Gdk.Color col = new Gdk.Color();
      Gdk.Color.Parse("black", ref col);
      a.ModifyBg(StateType.Normal, col);

      w.ShowAll ();

      Application.Run ();
    }

    static void close_window (object obj, DeleteEventArgs args)
    {
      Application.Quit ();
    }
  }

  public class CairoGraphic : DrawingArea
  {
    int[] font = new int[] {
      0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07,
      0x7f, 0x6f, 0x77, 0x7c, 0x58, 0x5e, 0x79, 0x71,
      0x3d, 0x74, 0x19, 0x0d, 0x76, 0x38, 0x36, 0x54,
      0x5c, 0x73, 0x67, 0x50, 0x6c, 0x78, 0x3e, 0x1c,
      0x7e, 0x14, 0x6e, 0x49, 0x00, 0x08, 0x40, 0x48
    };

    static void DrawRect(
      Cairo.Context g,
      double x,
      double y,
      double width,
      double height
      )
    {
      g.MoveTo ( x, y);
      g.LineTo ( x + width, y);
      g.LineTo ( x + width, y + height);
      g.LineTo ( x, y + height);
      g.ClosePath ();
    }

    static void Draw7Seg(
      Cairo.Context g,
      int c,
      double x,
      double y
      )
    {
      g.Save ();
      if ((c & 0x01) != 0) DrawRect (g, 30 + x, 10 + y, 50, 20); // xywh
      if ((c & 0x02) != 0) DrawRect (g, 80 + x, 30 + y, 20, 50);
      if ((c & 0x04) != 0) DrawRect (g, 80 + x, 100 + y, 20, 50);
      if ((c & 0x08) != 0) DrawRect (g, 30 + x, 150 + y, 50, 20);
      if ((c & 0x10) != 0) DrawRect (g, 10 + x, 100 + y, 20, 50);
      if ((c & 0x20) != 0) DrawRect (g, 10 + x, 30 + y, 20, 50);
      if ((c & 0x40) != 0) DrawRect (g, 30 + x, 80 + y, 50, 20);
      g.ClosePath ();
      g.Restore ();
    }

    protected override bool OnExposeEvent (Gdk.EventExpose args)  {
      using (Context g = Gdk.CairoHelper.Create (args.Window)){
        B316 x = new B316 ();
        for (int i = 0; i < x.a.Length; i++) {
          Draw7Seg (
            g,
            font [x.a [i] - 55],
            30 + 110 * (i % 5),
            30 + 180 * (i / 5));
        }
        g.SetSourceRGBA (1, 0, 1, 1);
        g.FillPreserve ();
      }
      return true;
    }
  }

  class B316 {
    public byte[] a = System.Text.Encoding.ASCII.GetBytes("HELLOWORLD");
  }

5. Кнопка

  using Gtk;
  using System;

  public class buttons
  {
    static Widget label_box(string filename, string label_text )
    {
      HBox box = new HBox(false, 0);
      box.BorderWidth =  2;

      Gtk.Image image = new Gtk.Image(filename);

      Label label = new Label (label_text);

      box.PackStart (image, false, false, 3);
      box.PackStart(label, false, false, 3);

      image.Show();
      label.Show();

      return box;
    }

    static void callback( object obj, EventArgs args)
    {
      Console.WriteLine("Hello again - cool button was pressed");
    }

    static void delete_event (object obj, DeleteEventArgs args)
    {
      Application.Quit();
    }

    public static void Main(string[] args)
    {
      Application.Init();
      Window window = new Window ("Pixmap'd Buttons!");
      window.DeleteEvent += delete_event;
      window.BorderWidth = 10;
      Button button = new Button();
      button.Clicked += callback;
      Widget box = label_box ("/opt/png/w.png", "cool button");
      box.Show();
      button.Add(box);
      button.Show();
      window.Add(button);
      window.ShowAll();

      Application.Run();
    }
  }

------------------------------------------------------------------------

Appendix A. using Statement (C# Reference)

  http://msdn.microsoft.com/en-us/library/yh598w02.aspx

Provides a convenient syntax that ensures the correct use of IDisposable objects.
Example

The following example shows how to use the using statement.

  using (Font font1 = new Font("Arial", 10.0f))
  {
      byte charset = font1.GdiCharSet;
  }

Remarks

File and Font are examples of managed types that access unmanaged resources (in this case file handles and device contexts). There are many other kinds of unmanaged resources and class library types that encapsulate them. All such types must implement the IDisposable interface.

As a rule, when you use an IDisposable object, you should declare and instantiate it in a using statement. The using statement calls the Dispose method on the object in the correct way, and (when you use it as shown earlier) it also causes the object itself to go out of scope as soon as Dispose is called. Within the using block, the object is read-only and cannot be modified or reassigned.

The using statement ensures that Dispose is called even if an exception occurs while you are calling methods on the object. You can achieve the same result by putting the object inside a try block and then calling Dispose in a finally block; in fact, this is how the using statement is translated by the compiler. The code example earlier expands to the following code at compile time (note the extra curly braces to create the limited scope for the object):

  {
    Font font1 = new Font("Arial", 10.0f);
    try
    {
      byte charset = font1.GdiCharSet;
    }
    finally
    {
      if (font1 != null)
        ((IDisposable)font1).Dispose();
    }
  }

Multiple instances of a type can be declared in a using statement, as shown in the following example.

  using (Font font3 = new Font("Arial", 10.0f),
              font4 = new Font("Arial", 10.0f))
  {
      // Use font3 and font4.
  }

You can instantiate the resource object and then pass the variable to the using statement, but this is not a best practice. In this case, the object remains in scope after control leaves the using block even though it will probably no longer have access to its unmanaged resources. In other words, it will no longer be fully initialized. If you try to use the object outside the using block, you risk causing an exception to be thrown. For this reason, it is generally better to instantiate the object in the using statement and limit its scope to the using block.

  Font font2 = new Font("Arial", 10.0f);
  using (font2) // not recommended
  {
      // use font2
  }
  // font2 is still in scope
  // but the method call throws an exception
  float f = font2.GetHeight();

C# Language Specification

For more information, see the C# Language Specification.

  http://msdn.microsoft.com/en-us/library/ms228593.aspx

The language specification is the definitive source for C# syntax and usage.

------------------------------------------------------------------------

Appendix B. ref (C# Reference)
Visual Studio 2013

  http://msdn.microsoft.com/en-us/library/14akc2c7.aspx

The ref keyword causes an argument to be passed by reference, not by value. The effect of passing by reference is that any change to the parameter in the called method is reflected in the calling method. For example, if the caller passes a local variable expression or an array element access expression, and the called method replaces the object to which the ref parameter refers, then the caller’s local variable or the array element now refer to the new object.

<<Note. Do not confuse the concept of passing by reference with the concept of reference types. The two concepts are not the same. A method parameter can be modified by ref regardless of whether it is a value type or a reference type. There is no boxing of a value type when it is passed by reference.

To use a ref parameter, both the method definition and the calling method must explicitly use the ref keyword, as shown in the following example.>>

  class RefExample
  {
      static void Method(ref int i)
      {
          // Rest the mouse pointer over i to verify that it is an int.
          // The following statement would cause a compiler error if i
          // were boxed as an object.
          i = i + 44;
      }

      static void Main()
      {
          int val = 1;
          Method(ref val);
          Console.WriteLine(val);

          // Output: 45
      }
  }

An argument that is passed to a ref parameter must be initialized before it is passed. This differs from out parameters, whose arguments do not have to be explicitly initialized before they are passed. For more information, see out.

Members of a class can't have signatures that differ only by ref and out. A compiler error occurs if the only difference between two members of a type is that one of them has a ref parameter and the other has an out parameter. The following code, for example, doesn't compile.

  class CS0663_Example
  {
      // Compiler error CS0663: "Cannot define overloaded
      // methods that differ only on ref and out".
      public void SampleMethod(out int i) { }
      public void SampleMethod(ref int i) { }
  }

However, overloading can be done when one method has a ref or out parameter and the other has a value parameter, as shown in the following example.

  class RefOverloadExample
  {
      public void SampleMethod(int i) { }
      public void SampleMethod(ref int i) { }
  }

In other situations that require signature matching, such as hiding or overriding, ref and out are part of the signature and don't match each other.

Properties are not variables. They are methods, and cannot be passed to ref parameters.

For information about how to pass arrays, see Passing Arrays Using ref and out (C# Programming Guide).

You can't use the ref and out keywords for the following kinds of methods:

  -- Async methods, which you define by using the async modifier.

  -- Iterator methods, which include a yield return or yield break statement.


Example

The previous examples demonstrate what happens when you pass value types by reference. You can also use the ref keyword to pass reference types. Passing a reference type by reference enables the called method to replace the object in the calling method to which the reference parameter refers. The storage location of the object is passed to the method as the value of the reference parameter. If you change the value in the storage location of the parameter (to point to a new object), you also change the storage location to which the caller refers. The following example passes an instance of a reference type as a ref parameter. For more information about how to pass reference types by value and by reference, see Passing Reference-Type Parameters (C# Programming Guide).

  class RefExample2
  {
      static void ChangeByReference(ref Product itemRef)
      {
          // The following line changes the address that is stored in
          // parameter itemRef. Because itemRef is a ref parameter, the
          // address that is stored in variable item in Main
          // also is changed.
          itemRef = new Product("Stapler", 99999);

          // You can change the value of one of the properties of
          // itemRef. The change happens to item in Main as well.
          itemRef.ItemID = 12345;
      }

      static void Main()
      {
          // Declare an instance of Product and display its initial values.
          Product item = new Product("Fasteners", 54321);
          System.Console.WriteLine(
              "Original values in Main.  Name: {0}, ID: {1}\n",
              item.ItemName, item.ItemID);

          // Send item to ChangeByReference as a ref argument.
          ChangeByReference(ref item);
          System.Console.WriteLine(
              "Back in Main.  Name: {0}, ID: {1}\n",
              item.ItemName, item.ItemID);
      }
  }

  class Product
  {
      public Product(string name, int newID)
      {
          ItemName = name;
          ItemID = newID;
      }

      public string ItemName { get; set; }
      public int ItemID { get; set; }
  }

  Output:

  Original values in Main.  Name: Fasteners, ID: 54321
  Back in Main.  Name: Stapler, ID: 12345

C# Language Specification

For more information, see the C# Language Specification. The language specification is the definitive source for C# syntax and usage.

------------------------------------------------------------------------

Ccылки
------

[1] http://www.netmf.com/get-started/

[2] http://shop.microframework.eu/Catalogue.aspx/gadgeteer
    https://www.youtube.com/watch?v=wQlTLNOCl90

[3] http://www.mountaineer.org/netmf-for-stm32/
    http://www.st.com/st-web-ui/static/active/en/resource/technical
         /document/user_manual/DM00096190.pdf
    http://habrahabr.ru/post/175989/

[4] http://xamarin.com/platform
    https://twitter.com/XamarinRobotics
    http://developer.xamarin.com/guides/cross-platform/robotics/

[5] http://en.wikipedia.org/wiki/.NET_Micro_Framework

[6] http://msdn.microsoft.com/en-us/library/ee435793.aspx

[7] http://zetcode.com/gui/gtksharp/drawing/

[8] http://www.mono-project.com/docs/tools+libraries/libraries
         /Mono.Cairo/cookbook/ (C)2015
    http://www.mono-project.com/docs/tools+libraries/libraries
         /Mono.Cairo/tutorial/ (C)2015
    http://www.mono-project.com/docs/gui/gtksharp/widgets/buttons/

[9] http://www.mono-project.com/docs/gui/gtksharp/widgets/widget-colours

Also:

  http://www.filewatcher.com/p/gtk-3-examples_3.6.1-1_armhf.deb.307550
    /usr/share/gtk-3.0/demo/colorsel.c.html
