summaryrefslogtreecommitdiff
path: root/multiplexer.c
blob: e4b2e11500cdf37d2415c70348842af1b527733f (plain)
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#ifndef SKIP_GPIO
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#endif
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <assert.h>

#include "multiplexer.h"

/** TODO
void printButton(int g)
{
  if (GET_GPIO(g)) // !=0 <-> bit is 1 <- port is HIGH=3.3V
    printf("Button pressed!\n");
  else // port is LOW=0V
    printf("Button released!\n");
} **/


//
// Set up a memory regions to access GPIO
//
int multiplexer_setup_root()
{
#ifndef SKIP_GPIO
  /* open /dev/mem */
  if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
    perror("can't open /dev/mem");
    return EXIT_FAILURE;
  }

  /* mmap GPIO */
  gpio_map = mmap(
    NULL,             //Any adddress in our space will do
    BLOCK_SIZE,       //Map length
    PROT_READ|PROT_WRITE,// Enable reading & writting to mapped memory
    MAP_SHARED,       //Shared with other processes
    mem_fd,           //File to map
    GPIO_BASE         //Offset to GPIO peripheral
  );

  close(mem_fd); //No need to keep mem_fd open after mmap

  if (gpio_map == MAP_FAILED) {
    perror("mmap error");
    return EXIT_FAILURE;
  }

  // Always use volatile pointer!
  gpio = (volatile unsigned *)gpio_map;
#endif
} // multiplexer_setup_root

//
// Shift the bits provided in content into the display
//
void *put_on_display(void *param)
{
  t_display_data *display_data = param;
  int line, column;

  while (display_data -> keep_running) {

#ifdef SKIP_GPIO
    usleep(10000);
    printf("=\n");
#endif
    display_data -> is_buf = display_data -> should_buf;
    for (line=0; line<7; line++) {
#ifdef SKIP_GPIO
      for (column=0; column<40; column++) {
        if (display_data -> buf[display_data -> is_buf][column] & (0x01 << line))
          printf("X");
        else
          printf(" ");
#else
      GPIO_CLR = 1<<GATE_PIN; // Licht an
      for (column=0; column<8; column++) {
        GPIO_CLR = 1<<SER_CLK_PIN;
        GPIO_ALTER(column == line) = 1<<SER_DAT_PIN;
        usleep(5);
        GPIO_SET = 1<<SER_CLK_PIN;
        usleep(5);
      }
      for (column=39; column>=0; column--) {
        GPIO_CLR = 1<<SER_CLK_PIN;
        GPIO_ALTER(display_data -> buf[display_data -> is_buf][column] & (0x01 << line)) = 1<<SER_DAT_PIN;
        usleep(5);
        GPIO_SET = 1<<SER_CLK_PIN;
        usleep(5);
#endif
      }
#ifdef SKIP_GPIO
      printf("\n");
#else
      GPIO_SET = 1<<GATE_PIN; // Licht aus
      usleep(5);
      GPIO_CLR = 1<<PAR_CLK_PIN;
      usleep(5);
      GPIO_SET = 1<<PAR_CLK_PIN;
#endif
    }
  }
  return NULL;
} // put_on_display

// scroll the text over the display
void *scroll_it(void *param)
{
  t_scroll_data *scroll_data = (t_scroll_data *) param;
  t_scroll_buffer buf[3];
  for (int i=0; i<3; i++)
    memset(&buf[i], 0, sizeof(buf[i]));
  t_display_data display_data;
  multiplexer_setup_non_root(&display_data);
  int is_buf = 0;
  int column = 0;
  while (scroll_data -> keep_running) {
    if (scroll_data -> update) {
      if ((buf[is_buf] . len != scroll_data -> input_len) || (memcmp(&buf[is_buf] . buf[buf[is_buf] . start], scroll_data -> input, scroll_data -> input_len) != 0)) {
        is_buf = (is_buf + 1) % 2;
        // copy the currently visible, old content
        memcpy(buf[is_buf] . buf, &buf[(is_buf + 1) % 2] . buf[column + 1], 39);
        buf[is_buf] . start = 39;
        // set the length of the new content
        buf[is_buf] . len = scroll_data -> input_len;
        // copy the new content from input
        for (int i=0; i<2; i++)
          memcpy(
            &buf[is_buf] . buf[39 + i * buf[is_buf] . len],
            scroll_data -> input,
            buf[is_buf] . len
          );
        column = 0;
      }
      // clear update flag
      scroll_data -> update = 0;
    }
    for (int i=0; i<40; i++)
      display_data . buf[(display_data . should_buf + 1) % 3][i] =
        buf[is_buf] . buf[column + i];
    display_data . should_buf = (display_data . should_buf + 1) % 3;
    column++;
    if (buf[is_buf] . len > 0)
      while (column >= buf[is_buf] . start + buf[is_buf] . len)
        column -= buf[is_buf] . len;
    usleep(50000);
  }
  display_data . keep_running = 0;
  pthread_join(display_data . thread_id, NULL);
} // scroll_it

void multiplexer_setup_non_root(t_display_data *display_data)
{
#ifndef SKIP_GPIO
  // must use INP_GPIO before we can use OUT_GPIO
  INP_GPIO(SER_DAT_PIN);
  OUT_GPIO(SER_DAT_PIN);
  INP_GPIO(SER_CLK_PIN);
  OUT_GPIO(SER_CLK_PIN);
  INP_GPIO(GATE_PIN);
  OUT_GPIO(GATE_PIN);
  INP_GPIO(PAR_CLK_PIN);
  OUT_GPIO(PAR_CLK_PIN);
  INP_GPIO(SENSE_PIN);
#endif

  for (int i=0; i<3; i++)
    memset(display_data -> buf[i],0,40);
  display_data -> is_buf = 0;
  display_data -> should_buf = 0;
  display_data -> keep_running = 1;
  pthread_create(&display_data -> thread_id, NULL, put_on_display, display_data);
  return;
} // multiplexer_setup_non_root

void multiplexer_setup_scroll(t_scroll_data *scroll_data)
{
  scroll_data -> update = 0;
  scroll_data -> keep_running = 1;
  pthread_create(&scroll_data -> thread_id, NULL, scroll_it, scroll_data);
  return;
} // multiplexer_setup_scroll