Landfall

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

254:a437381bd5f4
9 months ago Paul Boddie Employed get_channel to eliminate redundant code. cpm-library-improvements
paul@0 1
/*
paul@0 2
 * Access the keypad GPIOs on the Ben NanoNote.
paul@0 3
 *
paul@31 4
 * Copyright (C) 2018 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/devices/gpio-jz4740.h>
paul@0 23
#include <l4/re/c/util/video/goos_fb.h>
paul@0 24
#include <l4/re/c/video/view.h>
paul@0 25
#include <l4/util/util.h>
paul@0 26
paul@0 27
#include <unistd.h>
paul@0 28
#include <stdint.h>
paul@0 29
paul@0 30
#include "memory.h"
paul@0 31
paul@0 32
enum Jz4740_keypad_gpio
paul@0 33
{
paul@0 34
  Jz4740_keypad_gpio_inputs_count = 8,
paul@0 35
  Jz4740_keypad_gpio_outputs_count = 8,
paul@0 36
};
paul@0 37
paul@0 38
/* Port D input pins. */
paul@0 39
paul@0 40
const uint8_t Jz4740_keypad_inputs[Jz4740_keypad_gpio_inputs_count] = {
paul@0 41
  18, 19, 20, 21, 22, 23, 24, 26
paul@0 42
};
paul@0 43
paul@0 44
const Pin_slice Jz4740_keypad_inputs_mask = {.mask = 0x05fc0000, .offset = 0};
paul@0 45
paul@0 46
/* Port C output pins. */
paul@0 47
paul@0 48
const uint8_t Jz4740_keypad_outputs[Jz4740_keypad_gpio_outputs_count] = {
paul@0 49
  10, 11, 12, 13, 14, 15, 16, 17
paul@0 50
};
paul@0 51
paul@0 52
const Pin_slice Jz4740_keypad_outputs_mask = {.mask = 0x0003fc00, .offset = 0};
paul@0 53
paul@0 54
/* Video abstractions. */
paul@0 55
paul@0 56
static l4re_util_video_goos_fb_t gfb;
paul@0 57
static l4re_video_view_info_t fbi;
paul@0 58
static void *fb;
paul@0 59
paul@0 60
/* Peripheral memory regions. */
paul@0 61
paul@0 62
static l4_addr_t gpio_virt_base = 0, gpio_virt_base_end = 0;
paul@0 63
paul@0 64
/* GPIO abstractions. */
paul@0 65
paul@0 66
static void *gpio_port_c, *gpio_port_d;
paul@0 67
paul@0 68
/* Keypad status. */
paul@0 69
paul@0 70
uint8_t keypad[Jz4740_keypad_gpio_outputs_count];
paul@0 71
paul@0 72
paul@0 73
paul@0 74
/* Initialise the pins for scanning the keypad. */
paul@0 75
paul@0 76
static void init_keyscan(void)
paul@0 77
{
paul@0 78
  jz4740_gpio_multi_setup(gpio_port_d, &Jz4740_keypad_inputs_mask, Fix_input, 0);
paul@0 79
  jz4740_gpio_multi_config_pull(gpio_port_d, &Jz4740_keypad_inputs_mask, Pull_up);
paul@0 80
  jz4740_gpio_multi_setup(gpio_port_c, &Jz4740_keypad_outputs_mask, Fix_input, 0);
paul@0 81
}
paul@0 82
paul@0 83
/*
paul@0 84
Scan the keypad by enabling each output column and inspecting each input row.
paul@0 85
Store each column bitmap in the keypad array.
paul@0 86
*/
paul@0 87
paul@0 88
static void scan_keypad(void)
paul@0 89
{
paul@0 90
  uint8_t column, row, value;
paul@0 91
paul@0 92
  for (column = 0; column < Jz4740_keypad_gpio_outputs_count; column++)
paul@0 93
  {
paul@0 94
    jz4740_gpio_setup(gpio_port_c, Jz4740_keypad_outputs[column], Fix_output, 0);
paul@0 95
    l4_sleep(1);
paul@0 96
paul@0 97
    value = 0;
paul@0 98
paul@0 99
    for (row = 0; row < Jz4740_keypad_gpio_inputs_count; row++)
paul@0 100
      value = (value << 1) | (jz4740_gpio_get(gpio_port_d, Jz4740_keypad_inputs[row]) ? 0 : 1);
paul@0 101
paul@0 102
    keypad[column] = value;
paul@0 103
paul@0 104
    jz4740_gpio_setup(gpio_port_c, Jz4740_keypad_outputs[column], Fix_input, 0);
paul@0 105
  }
paul@0 106
}
paul@0 107
paul@0 108
static uint32_t bitmask(uint32_t size)
paul@0 109
{
paul@0 110
  return (1 << size) - 1;
paul@0 111
}
paul@0 112
paul@0 113
static uint32_t truncate_channel(uint32_t value, uint32_t size)
paul@0 114
{
paul@0 115
  return (value >> (8 - size)) & bitmask(size);
paul@0 116
}
paul@0 117
paul@0 118
static void set_pixel(uint32_t pos, uint8_t bpp, uint32_t value)
paul@0 119
{
paul@0 120
  if (bpp <= 8) *(uint8_t *) pos = value;
paul@0 121
  else if (bpp <= 16) *(uint16_t *) pos = value;
paul@0 122
  else *(uint32_t *) pos = value;
paul@0 123
}
paul@0 124
paul@0 125
/* Show the state of a key on the display. */
paul@0 126
paul@0 127
static void show_keystate(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t rgb)
paul@0 128
{
paul@0 129
  uint8_t bpp = l4re_video_bits_per_pixel(&fbi.pixel_info);
paul@0 130
  uint8_t bytes_per_pixel = fbi.pixel_info.bytes_per_pixel;
paul@0 131
  uint32_t bytes_per_line = fbi.bytes_per_line;
paul@0 132
  uint32_t pos;
paul@0 133
  uint32_t col, row;
paul@0 134
paul@0 135
  rgb = (truncate_channel(rgb >> 16, fbi.pixel_info.r.size) << fbi.pixel_info.r.shift) |
paul@0 136
        (truncate_channel(rgb >> 8, fbi.pixel_info.g.size) << fbi.pixel_info.g.shift) |
paul@0 137
        (truncate_channel(rgb, fbi.pixel_info.b.size) << fbi.pixel_info.b.shift);
paul@0 138
paul@0 139
  for (row = 0; row < h; row++)
paul@0 140
  {
paul@0 141
    pos = (uint32_t) fb + (y + row) * bytes_per_line + x * bytes_per_pixel;
paul@0 142
paul@0 143
    for (col = 0; col < w; col++)
paul@0 144
    {
paul@0 145
      set_pixel(pos, bpp, rgb);
paul@0 146
      pos += bytes_per_pixel;
paul@0 147
    }
paul@0 148
  }
paul@0 149
}
paul@0 150
paul@0 151
/* Show the keypad status on the display. */
paul@0 152
paul@0 153
static void show_keypad(void)
paul@0 154
{
paul@0 155
  uint32_t colsize = fbi.width / Jz4740_keypad_gpio_outputs_count,
paul@0 156
           rowsize = fbi.height / Jz4740_keypad_gpio_inputs_count;
paul@0 157
  uint8_t column, row;
paul@0 158
  uint32_t mask;
paul@0 159
paul@0 160
  for (column = 0; column < Jz4740_keypad_gpio_outputs_count; column++)
paul@0 161
paul@0 162
    for (row = 0, mask = 1 << (Jz4740_keypad_gpio_inputs_count - 1);
paul@0 163
         row < Jz4740_keypad_gpio_inputs_count;
paul@0 164
         row++, mask >>= 1)
paul@0 165
paul@0 166
      show_keystate(column * colsize, row * rowsize, colsize, rowsize,
paul@0 167
                    keypad[column] & mask ? 0xffffff : 0);
paul@0 168
paul@0 169
  /* Refresh the display. */
paul@0 170
paul@0 171
  l4re_util_video_goos_fb_refresh(&gfb, 0, 0, fbi.width, fbi.height);
paul@0 172
}
paul@0 173
paul@0 174
int main(void)
paul@0 175
{
paul@0 176
  int result;
paul@0 177
paul@0 178
  if ((result = get_memory("jz4740-gpio", &gpio_virt_base, &gpio_virt_base_end)) < 0)
paul@0 179
    return 1;
paul@0 180
paul@0 181
  if (l4re_util_video_goos_fb_setup_name(&gfb, "fb"))
paul@0 182
    return 1;
paul@0 183
paul@0 184
  if (l4re_util_video_goos_fb_view_info(&gfb, &fbi))
paul@0 185
    return 1;
paul@0 186
paul@0 187
  if (!(fb = l4re_util_video_goos_fb_attach_buffer(&gfb)))
paul@0 188
    return 1;
paul@0 189
paul@0 190
  gpio_port_c = jz4740_gpio_init(gpio_virt_base + 0x200, gpio_virt_base + 0x300, 32);
paul@0 191
  gpio_port_d = jz4740_gpio_init(gpio_virt_base + 0x300, gpio_virt_base + 0x400, 32);
paul@0 192
paul@0 193
  init_keyscan();
paul@0 194
paul@0 195
  while (1)
paul@0 196
  {
paul@0 197
    scan_keypad();
paul@0 198
    show_keypad();
paul@0 199
  }
paul@0 200
paul@0 201
  return 0;
paul@0 202
}