Saturday, April 28, 2018

text based user interface: termbox tutorial - 3. mouse input

When we talk about user interface, it is always about keyboard and mouse. In most cases, mouse is the most handy interface.

termbox provide the library to interact with mouse. It is simple and easy. For simple, it comes with missing feature. I was wrong; termbox is a great library. I will explain it at the latter part of blog.

For example, I need to click on the box which is comprised of few blocks. I named the block "ESC", I need to click in the very middle of each character, then only the mouse click event is detected.

Either way, it is still a good feature. Better than none.

As usual, paste the source code here.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include <stdio.h>
#include <string.h>
#include "../termbox.h"

struct key {
        unsigned char x;
        unsigned char y;
        uint32_t ch;
};

static const char chars_hw[] = "hello world";

#define STOP {0,0,0}
struct key K_ESC[] = {{1,1,'E'},{2,1,'S'},{3,1,'C'},STOP};
void draw_key(struct key *k, uint16_t fg, uint16_t bg)
{
        while (k->x) {
                tb_change_cell(k->x+2, k->y+4, k->ch, fg, bg);
                k++;
        }
}

int main(int argv, char **argc) {
        (void)argc; (void)argv;
        int code = tb_init();
        if (code < 0) {
                fprintf(stderr, "termbox init failed, code: %d\n", code);
                return -1;
        }

        tb_select_input_mode(TB_INPUT_ESC | TB_INPUT_MOUSE);
        tb_select_output_mode(TB_OUTPUT_256);
        tb_clear();

        int j, k;
        for (k = 0; k < 5; k++) {
                j = 0;
                while(chars_hw[j] != 0) {
                        tb_change_cell(j, k, chars_hw[j], 32+j, 231-k);
                        j++;
                }
        }

        draw_key(K_ESC, TB_WHITE, TB_BLUE);

        tb_present();

        for (;;) {
                struct tb_event ev;
                int mx = -1;
                int my = -1;
                int t = tb_poll_event(&ev);
                if (t == -1) {
                        tb_shutdown();
                        fprintf(stderr, "termbox poll event error\n");
                        return -1;
                }

                switch (t) {
                case TB_EVENT_KEY:
                        if (ev.key == TB_KEY_ESC) {
                                tb_shutdown();
                                return 0;
                        }
                        break;
                case TB_EVENT_MOUSE:
                        if (ev.key == TB_KEY_MOUSE_LEFT) {
                                mx = ev.x;
                                my = ev.y;

                                if((mx >= 3 && mx <= 5) && my == 5) {
                                        tb_shutdown();
                                        return 0;
                                }
                        }
                        break;
                }
        }
}

I created a development folder inside the termbox-master, directory as "termbox-master/src/development".

to compile - "gcc mouse.c ../termbox.c ../utf8.c -o mouse".

You will have the mouse binary file. Run that file "./mouse" and you will get the following:

After some trying, I noticed that I have to click twice in order to close the program. This is weird and most likely is my mistake, so I did some debugging and read the demo file - keyboard.c.

There are several input for mouse clicks:
TB_KEY_MOUSE_LEFT:
TB_KEY_MOUSE_MIDDLE:
TB_KEY_MOUSE_RIGHT:
TB_KEY_MOUSE_WHEEL_UP:
TB_KEY_MOUSE_RELEASE:

ah, ha. I need to have one click and one release, then only it is detected as valid mouse click.

I re-modify the program and adding detection for click and release:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
                case TB_EVENT_MOUSE:
                        if (ev.key == TB_KEY_MOUSE_LEFT)
                                detect_click = 1;

                        if (ev.key == TB_KEY_MOUSE_RELEASE)
                                detect_release = 1;

                                mx = ev.x;
                                my = ev.y;
                        if (detect_click == 1 && detect_release == 1) {
                                detect_click = 0;
                                detect_release = 0;
                                if((mx >= 3 && mx <= 5) && my == 5) {
                                        tb_shutdown();
                                        return 0;

                                }
                        }
                        break;
                }

After adding that, the program working fine without error.

Termbox is a great TUI library.


Sunday, April 15, 2018

msp430 revisit - ccs, gcc

It been a while since my last visit to msp430. MSP430 is a MCU line produced by Texas Instrument. It has low to high end range converge, from msp430g series to msp430f series, now adding msp430fr and msp432 series.

TI CCS IDE is the best ide/compiler that I had been using so far. The GUI is intuitive (it is forked out from eclipse). The TI plugin is stable and features rich. The forum support is fast and intensive. The debugger function is good to use and sturdy.

In addition, the TI launchpad series is cheap and equipped with powerful debugger. However, MSP430 series unable to penetrate the market as well as hobbyist community.

I not so sure about the industry usage, but I am guessing the price. During my previous employment in one of the international home appliance company, I noticed big company has strict control on the price, for every cent they save in a component, it will converts to a big lump sum in mass production. Using cheap MCU is not problem, the company has us (engineer) to solve the problem. This is where the engineer value come in. As engineer, considering same features and equivalent hardware quality, we need to look into the price first before considering other factors like tools, support.

The hobbyist side, Arduino has a good start. So it is hard to catch back. Arduino has huge fan base, large community support, world wide third party vendors. The library support all peripherals and wide range of modules, not to mention the control part. such as PID, CNC milling. The API is dummy and in English language instead of programming language. Not only beginner fond of it, the amateur use it heavily for proof of concept. MSP430 is lacking these types of advantageous.

MSP430 is relatively more complex compared with Microchip PIC18f series. University like to use PIC series for teaching materials, end up the student will use the same MCU after they out of university. Microchip MCU price also relatively cheaper compared with other US MCU manufacturers such as TI, Atmel.

To build up the competency in embedded system, it is good to start with MSP430. It has good support and documentation, you can always google or technical inquires in TI forum. Furthermore, the solidly built debugger ease the learning process as you can always read the register, global variable and putting break point to understand program flow. Arduino is a good start but I always have doubt on the so call "Arduino" expert. Unless you are the one who wrote the Arduino's library, else you are as good as primary school student who is expert in Arduino.

Due to my old PC setup, I am facing some issue when installing CCS8 and CCS7. I end up with CCS6. Still, it is a better version compared with CCS4. Took me quit a while to open CCS6. After it is loaded, CCS6 is functioning smoothly.

I have installed MSP430 GCC through the CCS plugin.
Help->Install New Software->--All Available Sites--->MSP430 GCC Tools->MSP430 GCC Tools (Window)

Manually close the CCS6 again after the MSP430 GCC is installed.

I am using MSP430f5529 launchpad.
Below is my source code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#include <msp430.h>

int main(void)
{
  WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog timer
  P1DIR |= BIT0;                            // Set P1.0 to output direction
  P1REN |= BIT1;                            // Enable P1.1 internal resistance
  P1OUT |= BIT1;                            // Set P1.1 as pull-Up resistance

  while (1)                                 // Test P1.1
  {
   if (P1IN & BIT1)
    P1OUT &= ~BIT0;                        // if P1.1 clear, set P1.0
   else
    P1OUT |= BIT0;                       // else reset
  }
}

Simply modification from the MSP430f5529 example code.

After compiled, click on the debug button.


It will connect to the on board debugger. It might took a while.

From my example, I am only dealing with port 1 pins. And, I can check the register directly through the view window.

Another convenient feature is changing the register value. You need to stop the program first before you can modify the register value.
For example, I am changing the pin1.0 high/low

The best part on changing pin register is the direct effect observed. The led is turned on and off.

Another good feature breakpoint, (actually all debuggers have this features, but TI one is much better)

And you can activate and deactivate the breakpoint through the GUI, life saver

I not sure how stable is the MSP430 GCC but never argue with free.

I will spent more time reading the MSP430 GCC documentation, in order to fully utilize this compiler.

I am trying to build a freertos demo. Nothing work and I have no idea why.

Wednesday, April 4, 2018

Reading schematic - Sparkfun Logic_Level_Bidirectional

Sparkfun bidirectional logic level converter is simple, cheap and effective in conversing between two voltage level.

It is amazing how two pull up resistors and N channel transistor can achieve bidirection communication between two voltage levels.

First, have a look at the circuit:

The gate of the BSS138 is connected to LV and both HV and LV are connected with 10kohm pull up resistor. 

Simple.   

There is only 4 scenarios, LV1 is high, LV1 is low, HV1 is high, HV1 is low. Let look at it one by one.

1. LV1 is low:
Assuming:
LV = 3.3V
HV = 5V
LV1 = 0 (ground)

I like to put figure in analysis.
From the picture above, current will flow from 3.3V to 0V, so we know that the R3 has voltage different of 3.3V.
Why?? 3.3V - 0V, we get 3.3V.

Now the BSS138 gate (G) and source (S) has voltage different of 3.3V. It will turn on the BSS138 and current from 5V will flow according to arrow 2.
In the same time, HV1 is connected to LV1, effectively HV1 is 0V.


2. LV1 is high:
Assuming:
LV = 3.3V
HV = 5V
LV1 = 3.3V
HV1 = ??

Now that LV and LV1 is 3.3V, there is not voltage different across R3, which in turn, indicate that Vgs is zero, BSS138 is not turned on.
Current from HV only able to flow to HV1. Assuming that the input resistance of HV1 is very high, HV1 will get approximately of 5V.


3. HV1 is low:

Assuming:
LV = 3.3V
HV = 5V
LV1 = ??
HV1 = 0V

from HV side, current is flowing according to arrow 1, 
at LV side, current will flow from 3.3V to HV1 because 
at this point, LV1 is approximately 3.3V
HV1 is equal to 0. 
There is potential different for the diode in BSS138, so current will flow through the diode in BSS138.
After the circuit is completed, LV1 = HV1, which is equal to 0.

4. HV1 is high:
Assuming:
LV = 3.3V
HV = 5V
LV1 = ??
HV1 = 5V

HV and HV1 has same voltage, no current will conduct.
3.3V from LV will not flow to HV1 cause HV1 has higher voltage than LV,
so the 3.3V will flow to LV1.
if assuming that the input resistance of LV1 is very high, LV1 will get approximately of 3.3V.

Draft version:
Will edit again