Landfall

Annotated pkg/landfall-examples/qi_lb60_keypad_physical/qi_lb60_keypad_physical.c

229:810ca800993b
11 months ago Paul Boddie Employ a picture representation compatible with 16-bit SPI transfers over DMA. cpm-library-improvements
paul@0 1
/*
paul@0 2
 * Display the physical keypad matrix layout for the Ben NanoNote.
paul@0 3
 *
paul@142 4
 * Copyright (C) 2018, 2023 Paul Boddie <paul@boddie.org.uk>
paul@0 5
 *
paul@0 6
 * This program is free software; you can redistribute it and/or
paul@0 7
 * modify it under the terms of the GNU General Public License as
paul@0 8
 * published by the Free Software Foundation; either version 2 of
paul@0 9
 * the License, or (at your option) any later version.
paul@0 10
 *
paul@0 11
 * This program is distributed in the hope that it will be useful,
paul@0 12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
paul@0 13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
paul@0 14
 * GNU General Public License for more details.
paul@0 15
 *
paul@0 16
 * You should have received a copy of the GNU General Public License
paul@0 17
 * along with this program; if not, write to the Free Software
paul@0 18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
paul@0 19
 * Boston, MA  02110-1301, USA
paul@0 20
 */
paul@0 21
paul@0 22
#include <l4/re/c/rm.h>
paul@0 23
#include <l4/re/env.h>
paul@0 24
paul@0 25
#include <l4/re/c/util/video/goos_fb.h>
paul@0 26
#include <l4/re/c/video/view.h>
paul@0 27
paul@0 28
#include <unistd.h>
paul@0 29
#include <stdint.h>
paul@0 30
#include <stdlib.h>
paul@0 31
paul@157 32
#include "keypad_client.h"
paul@157 33
paul@157 34
paul@157 35
paul@0 36
enum Jz4740_keypad_gpio
paul@0 37
{
paul@0 38
  Jz4740_keypad_gpio_inputs_count = 8,
paul@0 39
  Jz4740_keypad_gpio_outputs_count = 8,
paul@0 40
};
paul@0 41
paul@0 42
/* Video abstractions. */
paul@0 43
paul@0 44
static l4re_util_video_goos_fb_t gfb;
paul@0 45
static l4re_video_view_info_t fbi;
paul@0 46
static void *fb;
paul@0 47
paul@0 48
/* Keypad status and dimensions. */
paul@0 49
paul@157 50
uint32_t *keymem = 0;
paul@0 51
int columns = Jz4740_keypad_gpio_outputs_count, rows = Jz4740_keypad_gpio_inputs_count;
paul@0 52
paul@0 53
/* Position units. */
paul@0 54
paul@0 55
enum {
paul@0 56
  KEY = 12, DIRKEY = 8,
paul@0 57
  WIDTH = 120, HEIGHT = 72, ROWS = 6,
paul@0 58
};
paul@0 59
paul@0 60
/*
paul@0 61
        F1  F2  F3  F4  F5  F6  F7  F8
paul@0 62
Q   W   E   R   T   Y   U   I   O   P
paul@0 63
A   S   D   F   G   H   J   K   L   Bsp
paul@0 64
Esc Z   X   C   V   B   N   M   =   Enter
paul@0 65
Tab Cap \   '   ,   .   /      Up   V-Up
paul@0 66
LSh LAl Fn  Sym Spc Qi Ctr Lt Dn Rt V-Dn
paul@0 67
*/
paul@0 68
paul@0 69
enum {
paul@0 70
  SIZE_KEY_F1 = KEY, SIZE_KEY_F2 = KEY, SIZE_KEY_F3 = KEY, SIZE_KEY_F4 = KEY,
paul@0 71
  SIZE_KEY_F5 = KEY, SIZE_KEY_F6 = KEY, SIZE_KEY_F7 = KEY, SIZE_KEY_F8 = KEY,
paul@0 72
paul@0 73
  SIZE_KEY_Q = KEY, SIZE_KEY_W = KEY, SIZE_KEY_E = KEY, SIZE_KEY_R = KEY,
paul@0 74
  SIZE_KEY_T = KEY, SIZE_KEY_Y = KEY, SIZE_KEY_U = KEY, SIZE_KEY_I = KEY,
paul@0 75
  SIZE_KEY_O = KEY, SIZE_KEY_P = KEY,
paul@0 76
paul@0 77
  SIZE_KEY_A = KEY, SIZE_KEY_S = KEY, SIZE_KEY_D = KEY, SIZE_KEY_F = KEY,
paul@0 78
  SIZE_KEY_G = KEY, SIZE_KEY_H = KEY, SIZE_KEY_J = KEY, SIZE_KEY_K = KEY,
paul@0 79
  SIZE_KEY_L = KEY, SIZE_KEY_BACKSPACE = KEY,
paul@0 80
paul@0 81
  SIZE_KEY_ESCAPE = KEY, SIZE_KEY_Z = KEY, SIZE_KEY_X = KEY, SIZE_KEY_C = KEY,
paul@0 82
  SIZE_KEY_V = KEY, SIZE_KEY_B = KEY, SIZE_KEY_N = KEY, SIZE_KEY_M = KEY,
paul@0 83
  SIZE_KEY_EQUAL = KEY, SIZE_KEY_ENTER = KEY,
paul@0 84
paul@0 85
  SIZE_KEY_TAB = KEY, SIZE_KEY_DOWNSHIFT = KEY, SIZE_KEY_BACKSLASH = KEY, SIZE_KEY_APOSTROPHE = KEY,
paul@0 86
  SIZE_KEY_COMMA = KEY, SIZE_KEY_DOT = KEY, SIZE_KEY_SLASH = KEY,
paul@0 87
  SIZE_KEY_UP = DIRKEY, SIZE_KEY_VOLUMEUP = KEY,
paul@0 88
paul@0 89
  SIZE_KEY_LEFTSHIFT = KEY, SIZE_KEY_LEFTALT = KEY, SIZE_KEY_FN = KEY, SIZE_KEY_SYM = KEY,
paul@0 90
  SIZE_KEY_SPACE = KEY, SIZE_KEY_QI = KEY, SIZE_KEY_RIGHTCTRL = KEY, SIZE_KEY_LEFT = DIRKEY,
paul@0 91
  SIZE_KEY_DOWN = DIRKEY, SIZE_KEY_RIGHT = DIRKEY, SIZE_KEY_VOLUMEDOWN = KEY,
paul@0 92
};
paul@0 93
paul@0 94
enum {
paul@0 95
  XPOS_KEY_F1 = 2*KEY, XPOS_KEY_F2 = 3*KEY, XPOS_KEY_F3 = 4*KEY, XPOS_KEY_F4 = 5*KEY,
paul@0 96
  XPOS_KEY_F5 = 6*KEY, XPOS_KEY_F6 = 7*KEY, XPOS_KEY_F7 = 8*KEY, XPOS_KEY_F8 = 9*KEY,
paul@0 97
paul@0 98
  XPOS_KEY_Q = 0, XPOS_KEY_W = KEY, XPOS_KEY_E = 2*KEY, XPOS_KEY_R = 3*KEY,
paul@0 99
  XPOS_KEY_T = 4*KEY, XPOS_KEY_Y = 5*KEY, XPOS_KEY_U = 6*KEY, XPOS_KEY_I = 7*KEY,
paul@0 100
  XPOS_KEY_O = 8*KEY, XPOS_KEY_P = 9*KEY,
paul@0 101
paul@0 102
  XPOS_KEY_A = 0, XPOS_KEY_S = KEY, XPOS_KEY_D = 2*KEY, XPOS_KEY_F = 3*KEY,
paul@0 103
  XPOS_KEY_G = 4*KEY, XPOS_KEY_H = 5*KEY, XPOS_KEY_J = 6*KEY, XPOS_KEY_K = 7*KEY,
paul@0 104
  XPOS_KEY_L = 8*KEY, XPOS_KEY_BACKSPACE = 9*KEY,
paul@0 105
paul@0 106
  XPOS_KEY_ESCAPE = 0, XPOS_KEY_Z = KEY, XPOS_KEY_X = 2*KEY, XPOS_KEY_C = 3*KEY,
paul@0 107
  XPOS_KEY_V = 4*KEY, XPOS_KEY_B = 5*KEY, XPOS_KEY_N = 6*KEY, XPOS_KEY_M = 7*KEY,
paul@0 108
  XPOS_KEY_EQUAL = 8*KEY, XPOS_KEY_ENTER = 9*KEY,
paul@0 109
paul@0 110
  XPOS_KEY_TAB = 0, XPOS_KEY_DOWNSHIFT = KEY, XPOS_KEY_BACKSLASH = 2*KEY, XPOS_KEY_APOSTROPHE = 3*KEY,
paul@0 111
  XPOS_KEY_COMMA = 4*KEY, XPOS_KEY_DOT = 5*KEY, XPOS_KEY_SLASH = 6*KEY,
paul@0 112
  XPOS_KEY_UP = 7*KEY+DIRKEY, XPOS_KEY_VOLUMEUP = 9*KEY,
paul@0 113
paul@0 114
  XPOS_KEY_LEFTSHIFT = 0, XPOS_KEY_LEFTALT = KEY, XPOS_KEY_FN = 2*KEY, XPOS_KEY_SYM = 3*KEY,
paul@0 115
  XPOS_KEY_SPACE = 4*KEY, XPOS_KEY_QI = 5*KEY, XPOS_KEY_RIGHTCTRL = 6*KEY, XPOS_KEY_LEFT = 7*KEY,
paul@0 116
  XPOS_KEY_DOWN = 7*KEY+DIRKEY, XPOS_KEY_RIGHT = 7*KEY+2*DIRKEY, XPOS_KEY_VOLUMEDOWN = 9*KEY,
paul@0 117
};
paul@0 118
paul@0 119
enum {
paul@0 120
  YPOS_KEY_F1 = 0, YPOS_KEY_F2 = 0, YPOS_KEY_F3 = 0, YPOS_KEY_F4 = 0,
paul@0 121
  YPOS_KEY_F5 = 0, YPOS_KEY_F6 = 0, YPOS_KEY_F7 = 0, YPOS_KEY_F8 = 0,
paul@0 122
paul@0 123
  YPOS_KEY_Q = 1, YPOS_KEY_W = 1, YPOS_KEY_E = 1, YPOS_KEY_R = 1,
paul@0 124
  YPOS_KEY_T = 1, YPOS_KEY_Y = 1, YPOS_KEY_U = 1, YPOS_KEY_I = 1,
paul@0 125
  YPOS_KEY_O = 1, YPOS_KEY_P = 1,
paul@0 126
paul@0 127
  YPOS_KEY_A = 2, YPOS_KEY_S = 2, YPOS_KEY_D = 2, YPOS_KEY_F = 2,
paul@0 128
  YPOS_KEY_G = 2, YPOS_KEY_H = 2, YPOS_KEY_J = 2, YPOS_KEY_K = 2,
paul@0 129
  YPOS_KEY_L = 2, YPOS_KEY_BACKSPACE = 2,
paul@0 130
paul@0 131
  YPOS_KEY_ESCAPE = 3, YPOS_KEY_Z = 3, YPOS_KEY_X = 3, YPOS_KEY_C = 3,
paul@0 132
  YPOS_KEY_V = 3, YPOS_KEY_B = 3, YPOS_KEY_N = 3, YPOS_KEY_M = 3,
paul@0 133
  YPOS_KEY_EQUAL = 3, YPOS_KEY_ENTER = 3,
paul@0 134
paul@0 135
  YPOS_KEY_TAB = 4, YPOS_KEY_DOWNSHIFT = 4, YPOS_KEY_BACKSLASH = 4, YPOS_KEY_APOSTROPHE = 4,
paul@0 136
  YPOS_KEY_COMMA = 4, YPOS_KEY_DOT = 4, YPOS_KEY_SLASH = 4,
paul@0 137
  YPOS_KEY_UP = 4, YPOS_KEY_VOLUMEUP = 4,
paul@0 138
paul@0 139
  YPOS_KEY_LEFTSHIFT = 5, YPOS_KEY_LEFTALT = 5, YPOS_KEY_FN = 5, YPOS_KEY_SYM = 5,
paul@0 140
  YPOS_KEY_SPACE = 5, YPOS_KEY_QI = 5, YPOS_KEY_RIGHTCTRL = 5, YPOS_KEY_LEFT = 5,
paul@0 141
  YPOS_KEY_DOWN = 5, YPOS_KEY_RIGHT = 5, YPOS_KEY_VOLUMEDOWN = 5,
paul@0 142
};
paul@0 143
paul@0 144
/* Keypad matrix mapping. */
paul@0 145
paul@0 146
#define PHYS_KEY(X) {XPOS_KEY_##X, YPOS_KEY_##X, SIZE_KEY_##X}
paul@0 147
#define PHYS_NULL   {0, 0, 0}
paul@0 148
paul@0 149
static const uint32_t keypos[Jz4740_keypad_gpio_inputs_count][Jz4740_keypad_gpio_outputs_count][3] = {
paul@0 150
paul@0 151
{PHYS_KEY(F1), PHYS_KEY(F2), PHYS_KEY(F3), PHYS_KEY(F4), PHYS_KEY(F5), PHYS_KEY(F6),
paul@0 152
 PHYS_KEY(F7), PHYS_NULL},
paul@0 153
paul@0 154
{PHYS_KEY(Q), PHYS_KEY(W), PHYS_KEY(E), PHYS_KEY(R), PHYS_KEY(T), PHYS_KEY(Y),
paul@0 155
 PHYS_KEY(U), PHYS_KEY(I)},
paul@0 156
paul@0 157
{PHYS_KEY(A), PHYS_KEY(S), PHYS_KEY(D), PHYS_KEY(F), PHYS_KEY(G), PHYS_KEY(H),
paul@0 158
 PHYS_KEY(J), PHYS_KEY(K)},
paul@0 159
paul@0 160
{PHYS_KEY(ESCAPE), PHYS_KEY(Z), PHYS_KEY(X), PHYS_KEY(C), PHYS_KEY(V), PHYS_KEY(B),
paul@0 161
 PHYS_KEY(N), PHYS_KEY(M)},
paul@0 162
paul@0 163
{PHYS_KEY(TAB), PHYS_KEY(DOWNSHIFT) /* CAPSLOCK */, PHYS_KEY(BACKSLASH),
paul@0 164
 PHYS_KEY(APOSTROPHE), PHYS_KEY(COMMA), PHYS_KEY(DOT), PHYS_KEY(SLASH), PHYS_KEY(UP)},
paul@0 165
paul@0 166
{PHYS_KEY(O), PHYS_KEY(L), PHYS_KEY(EQUAL), PHYS_KEY(SYM) /* RIGHTALT */,
paul@0 167
 PHYS_KEY(SPACE), PHYS_KEY(QI) /* F13 */, PHYS_KEY(RIGHTCTRL), PHYS_KEY(LEFT)},
paul@0 168
paul@0 169
{PHYS_KEY(F8), PHYS_KEY(P), PHYS_KEY(BACKSPACE), PHYS_KEY(ENTER), PHYS_KEY(VOLUMEUP),
paul@0 170
 PHYS_KEY(VOLUMEDOWN), PHYS_KEY(DOWN), PHYS_KEY(RIGHT)},
paul@0 171
paul@0 172
{PHYS_KEY(LEFTSHIFT), PHYS_KEY(LEFTALT), PHYS_KEY(FN), PHYS_NULL, PHYS_NULL,
paul@0 173
 PHYS_NULL, PHYS_NULL, PHYS_NULL}
paul@0 174
};
paul@0 175
paul@0 176
paul@0 177
paul@0 178
static uint32_t bitmask(uint32_t size)
paul@0 179
{
paul@0 180
  return (1 << size) - 1;
paul@0 181
}
paul@0 182
paul@0 183
static uint32_t truncate_channel(uint32_t value, uint32_t size)
paul@0 184
{
paul@0 185
  return (value >> (8 - size)) & bitmask(size);
paul@0 186
}
paul@0 187
paul@0 188
static void set_pixel(uint32_t pos, uint8_t bpp, uint32_t value)
paul@0 189
{
paul@0 190
  if (bpp <= 8) *(uint8_t *) pos = value;
paul@0 191
  else if (bpp <= 16) *(uint16_t *) pos = value;
paul@0 192
  else *(uint32_t *) pos = value;
paul@0 193
}
paul@0 194
paul@0 195
/* Show the state of a key on the display. */
paul@0 196
paul@0 197
static void fill_rectangle(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t rgb)
paul@0 198
{
paul@0 199
  uint8_t bpp = l4re_video_bits_per_pixel(&fbi.pixel_info);
paul@0 200
  uint8_t bytes_per_pixel = fbi.pixel_info.bytes_per_pixel;
paul@0 201
  uint32_t bytes_per_line = fbi.bytes_per_line;
paul@0 202
  uint32_t pos;
paul@0 203
  uint32_t col, row;
paul@0 204
paul@0 205
  rgb = (truncate_channel(rgb >> 16, fbi.pixel_info.r.size) << fbi.pixel_info.r.shift) |
paul@0 206
        (truncate_channel(rgb >> 8, fbi.pixel_info.g.size) << fbi.pixel_info.g.shift) |
paul@0 207
        (truncate_channel(rgb, fbi.pixel_info.b.size) << fbi.pixel_info.b.shift);
paul@0 208
paul@0 209
  for (row = 0; row < h; row++)
paul@0 210
  {
paul@0 211
    pos = (uint32_t) fb + (y + row) * bytes_per_line + x * bytes_per_pixel;
paul@0 212
paul@0 213
    for (col = 0; col < w; col++)
paul@0 214
    {
paul@0 215
      set_pixel(pos, bpp, rgb);
paul@0 216
      pos += bytes_per_pixel;
paul@0 217
    }
paul@0 218
  }
paul@0 219
}
paul@0 220
paul@0 221
/* Show the keypad status on the display. */
paul@0 222
paul@0 223
static void show_keypad(void)
paul@0 224
{
paul@0 225
  uint32_t rowsize = fbi.height / ROWS, colsize;
paul@0 226
  uint8_t column, row;
paul@0 227
  uint32_t mask;
paul@0 228
  const uint32_t *pos;
paul@0 229
paul@0 230
  for (column = 0; column < columns; column++)
paul@0 231
 
paul@0 232
    for (row = 0, mask = 1 << (rows - 1);
paul@0 233
         row < rows;
paul@0 234
         row++, mask >>= 1)
paul@0 235
    {
paul@0 236
      /* Obtain the physical position. */
paul@0 237
paul@0 238
      pos = keypos[row][column];
paul@0 239
paul@0 240
      /* Obtain the width of the key. */
paul@0 241
paul@0 242
      colsize = (pos[2] * fbi.width) / WIDTH;
paul@0 243
paul@0 244
      /* Plot the rectangle for the key. */
paul@0 245
paul@0 246
      fill_rectangle((pos[0] * fbi.width) / WIDTH, pos[1] * rowsize, colsize, rowsize,
paul@157 247
                     keymem[column] & mask ? 0xffffff : 0);
paul@0 248
    }
paul@0 249
paul@0 250
  /* Refresh the display. */
paul@0 251
paul@0 252
  l4re_util_video_goos_fb_refresh(&gfb, 0, 0, fbi.width, fbi.height);
paul@0 253
}
paul@0 254
paul@0 255
paul@0 256
paul@0 257
int main(void)
paul@0 258
{
paul@157 259
  l4_cap_idx_t keypad_cap;
paul@0 260
  l4re_ds_t mem;
paul@0 261
paul@0 262
  if (l4re_util_video_goos_fb_setup_name(&gfb, "fb"))
paul@0 263
    return 1;
paul@0 264
paul@0 265
  if (l4re_util_video_goos_fb_view_info(&gfb, &fbi))
paul@0 266
    return 1;
paul@0 267
paul@0 268
  if (!(fb = l4re_util_video_goos_fb_attach_buffer(&gfb)))
paul@0 269
    return 1;
paul@0 270
paul@0 271
  /* Obtain a reference to the keypad. */
paul@0 272
paul@157 273
  keypad_cap = l4re_env_get_cap("keypad");
paul@0 274
paul@157 275
  if (l4_is_invalid_cap(keypad_cap))
paul@157 276
    return 1;
paul@0 277
paul@0 278
  /* Obtain a reference to the keypad data. */
paul@0 279
paul@157 280
  Keypad keypad = {.ref={.cap=keypad_cap}, .iface=&client_iface_Keypad};
paul@0 281
paul@157 282
  if (keypad.iface->get_keypad_data(keypad.ref, &mem))
paul@157 283
    return 1;
paul@0 284
paul@0 285
  /* Attach the keypad data to a region in this task. */
paul@0 286
paul@157 287
  if (l4re_rm_attach((void **) &keymem, l4re_ds_size(mem),
paul@145 288
                     L4RE_RM_F_SEARCH_ADDR | L4RE_RM_F_R,
paul@145 289
                     mem, 0,
paul@0 290
                     L4_PAGESHIFT))
paul@0 291
    return 1;
paul@0 292
paul@0 293
  /* Show the keypad state. */
paul@0 294
paul@157 295
  while (1)
paul@157 296
    show_keypad();
paul@0 297
paul@0 298
  return 0;
paul@0 299
}