| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | #  You may distribute under the terms of either the GNU General Public License | 
| 2 |  |  |  |  |  |  | #  or the Artistic License (the same terms as Perl itself) | 
| 3 |  |  |  |  |  |  | # | 
| 4 |  |  |  |  |  |  | #  (C) Paul Evans, 2020-2022 -- leonerd@leonerd.org.uk | 
| 5 |  |  |  |  |  |  |  | 
| 6 | 8 |  |  | 8 |  | 895104 | use v5.26; # signatures | 
|  | 8 |  |  |  |  | 99 |  | 
| 7 | 8 |  |  | 8 |  | 664 | use Object::Pad 0.66; | 
|  | 8 |  |  |  |  | 10933 |  | 
|  | 8 |  |  |  |  | 39 |  | 
| 8 |  |  |  |  |  |  |  | 
| 9 |  |  |  |  |  |  | package Device::Chip::NoritakeGU_D 0.05; | 
| 10 |  |  |  |  |  |  | class Device::Chip::NoritakeGU_D | 
| 11 | 1 |  |  | 1 |  | 635 | :isa(Device::Chip); | 
|  | 1 |  |  |  |  | 18876 |  | 
|  | 1 |  |  |  |  | 37 |  | 
| 12 |  |  |  |  |  |  |  | 
| 13 | 8 |  |  | 8 |  | 2398 | use Carp; | 
|  | 8 |  |  |  |  | 29 |  | 
|  | 8 |  |  |  |  | 470 |  | 
| 14 |  |  |  |  |  |  |  | 
| 15 | 8 |  |  | 8 |  | 52 | use Future::AsyncAwait; | 
|  | 8 |  |  |  |  | 17 |  | 
|  | 8 |  |  |  |  | 44 |  | 
| 16 | 8 |  |  | 8 |  | 376 | use List::Util qw( first ); | 
|  | 8 |  |  |  |  | 17 |  | 
|  | 8 |  |  |  |  | 9965 |  | 
| 17 |  |  |  |  |  |  |  | 
| 18 |  |  |  |  |  |  | =encoding UTF-8 | 
| 19 |  |  |  |  |  |  |  | 
| 20 |  |  |  |  |  |  | =head1 NAME | 
| 21 |  |  |  |  |  |  |  | 
| 22 |  |  |  |  |  |  | C - chip driver for F F display modules | 
| 23 |  |  |  |  |  |  |  | 
| 24 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 25 |  |  |  |  |  |  |  | 
| 26 |  |  |  |  |  |  | use Device::Chip::NoritakeGU_D; | 
| 27 |  |  |  |  |  |  | use Future::AsyncAwait; | 
| 28 |  |  |  |  |  |  |  | 
| 29 |  |  |  |  |  |  | my $chip = Device::Chip::NoritakeGU_D->new( interface => "UART" ); | 
| 30 |  |  |  |  |  |  | await $chip->mount( Device::Chip::Adapter::...->new ); | 
| 31 |  |  |  |  |  |  |  | 
| 32 |  |  |  |  |  |  | await $chip->text( "Hello, world!" ); | 
| 33 |  |  |  |  |  |  |  | 
| 34 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 35 |  |  |  |  |  |  |  | 
| 36 |  |  |  |  |  |  | This L subclass provides communication to a display module in | 
| 37 |  |  |  |  |  |  | the F family by F. | 
| 38 |  |  |  |  |  |  |  | 
| 39 |  |  |  |  |  |  | The reader is presumed to be familiar with the general operation of this chip; | 
| 40 |  |  |  |  |  |  | the documentation here will not attempt to explain or define chip-specific | 
| 41 |  |  |  |  |  |  | concepts or features, only the use of this module to access them. | 
| 42 |  |  |  |  |  |  |  | 
| 43 |  |  |  |  |  |  | =cut | 
| 44 |  |  |  |  |  |  |  | 
| 45 |  |  |  |  |  |  | =head1 CONSTRUCTOR | 
| 46 |  |  |  |  |  |  |  | 
| 47 |  |  |  |  |  |  | =cut | 
| 48 |  |  |  |  |  |  |  | 
| 49 |  |  |  |  |  |  | =head2 new | 
| 50 |  |  |  |  |  |  |  | 
| 51 |  |  |  |  |  |  | $chip = Device::Chip::NoritakeGU_D->new( | 
| 52 |  |  |  |  |  |  | interface => $iface, | 
| 53 |  |  |  |  |  |  | ... | 
| 54 |  |  |  |  |  |  | ) | 
| 55 |  |  |  |  |  |  |  | 
| 56 |  |  |  |  |  |  | Constructs a new driver instance for the given interface type. The type must | 
| 57 |  |  |  |  |  |  | be one of C, C or C. | 
| 58 |  |  |  |  |  |  |  | 
| 59 |  |  |  |  |  |  | =cut | 
| 60 |  |  |  |  |  |  |  | 
| 61 |  |  |  |  |  |  | my %INTERFACES = ( | 
| 62 |  |  |  |  |  |  | UART => 1, I2C => 1, SPI => 1, | 
| 63 |  |  |  |  |  |  | ); | 
| 64 |  |  |  |  |  |  |  | 
| 65 |  |  |  |  |  |  | field $_protocol  :param(interface); | 
| 66 |  |  |  |  |  |  | field $_interface; | 
| 67 |  |  |  |  |  |  |  | 
| 68 |  |  |  |  |  |  | ADJUST | 
| 69 |  |  |  |  |  |  | { | 
| 70 |  |  |  |  |  |  | $INTERFACES{$_protocol} or | 
| 71 |  |  |  |  |  |  | croak "Unrecognised interface type '$_protocol'"; | 
| 72 |  |  |  |  |  |  |  | 
| 73 |  |  |  |  |  |  | my $iface_class = __PACKAGE__."::_Iface::$_protocol"; | 
| 74 |  |  |  |  |  |  | $_interface = $iface_class->new; | 
| 75 |  |  |  |  |  |  | } | 
| 76 |  |  |  |  |  |  |  | 
| 77 | 7 |  |  | 7 | 0 | 118 | method PROTOCOL { $_protocol } | 
|  | 7 |  |  |  |  | 27 |  | 
| 78 |  |  |  |  |  |  |  | 
| 79 | 7 |  |  | 7 |  | 2498 | *UART_options = *I2C_options = *SPI_options = method { $_interface->options }; | 
|  | 7 |  |  |  |  | 30 |  | 
| 80 |  |  |  |  |  |  |  | 
| 81 |  |  |  |  |  |  | # passthrough | 
| 82 |  |  |  |  |  |  | method power | 
| 83 | 0 |  |  | 0 | 0 | 0 | { | 
| 84 | 0 | 0 |  |  |  | 0 | return $self->protocol->power( @_ ) if $self->protocol->can( "power" ); | 
| 85 | 0 |  |  |  |  | 0 | return Future->done; | 
| 86 |  |  |  |  |  |  | } | 
| 87 |  |  |  |  |  |  |  | 
| 88 | 7 |  |  |  |  | 22 | method mount ( $adapter, %params ) | 
|  | 7 |  |  |  |  | 18 |  | 
|  | 7 |  |  |  |  | 13 |  | 
|  | 7 |  |  |  |  | 14 |  | 
| 89 | 7 |  |  | 7 | 1 | 499 | { | 
| 90 | 7 |  |  |  |  | 37 | $_interface->mountopts( \%params ); | 
| 91 |  |  |  |  |  |  |  | 
| 92 | 7 |  |  |  |  | 51 | return $self->SUPER::mount( $adapter, %params ); | 
| 93 |  |  |  |  |  |  | } | 
| 94 |  |  |  |  |  |  |  | 
| 95 | 15 |  |  | 15 | 0 | 54 | method write { $_interface->write( $self, @_ ) } | 
|  | 15 |  |  |  |  | 63 |  | 
| 96 | 5 |  |  | 5 | 0 | 11190 | method read  { $_interface->read ( $self, @_ ) } | 
|  | 5 |  |  |  |  | 28 |  | 
| 97 |  |  |  |  |  |  |  | 
| 98 | 6 |  |  | 6 | 0 | 18 | method write_us { $self->write( pack "C*", 0x1F, @_ ) } | 
|  | 6 |  |  |  |  | 45 |  | 
| 99 |  |  |  |  |  |  |  | 
| 100 |  |  |  |  |  |  | =head1 METHODS | 
| 101 |  |  |  |  |  |  |  | 
| 102 |  |  |  |  |  |  | The following methods documented in an C expression return L | 
| 103 |  |  |  |  |  |  | instances. | 
| 104 |  |  |  |  |  |  |  | 
| 105 |  |  |  |  |  |  | =cut | 
| 106 |  |  |  |  |  |  |  | 
| 107 |  |  |  |  |  |  | =head2 text | 
| 108 |  |  |  |  |  |  |  | 
| 109 |  |  |  |  |  |  | await $chip->text( $str ); | 
| 110 |  |  |  |  |  |  |  | 
| 111 |  |  |  |  |  |  | Draw text at the cursor position. | 
| 112 |  |  |  |  |  |  |  | 
| 113 |  |  |  |  |  |  | =cut | 
| 114 |  |  |  |  |  |  |  | 
| 115 | 3 |  |  |  |  | 15 | async method text ( $text ) | 
|  | 3 |  |  |  |  | 9 |  | 
|  | 3 |  |  |  |  | 6 |  | 
| 116 | 3 |  |  |  |  | 13 | { | 
| 117 |  |  |  |  |  |  | # Don't allow C0 controls | 
| 118 | 3 | 50 |  |  |  | 17 | $text =~ m/[\x00-\x1F]/ and | 
| 119 |  |  |  |  |  |  | croak "Invalid characters for ->text"; | 
| 120 |  |  |  |  |  |  |  | 
| 121 | 3 |  |  |  |  | 14 | await $self->write( $text ); | 
| 122 | 3 |  |  | 3 | 1 | 957 | } | 
| 123 |  |  |  |  |  |  |  | 
| 124 | 16 |  |  |  |  | 31 | sub BOOL_COMMAND ( $name, @bytes ) | 
| 125 | 16 |  |  | 16 | 0 | 24 | { | 
|  | 16 |  |  |  |  | 27 |  | 
|  | 16 |  |  |  |  | 189 |  | 
| 126 | 16 |  |  |  |  | 27 | my $lastbyte = pop @bytes; | 
| 127 |  |  |  |  |  |  |  | 
| 128 | 8 |  |  | 8 |  | 69 | no strict 'refs'; | 
|  | 8 |  |  |  |  | 17 |  | 
|  | 8 |  |  |  |  | 2042 |  | 
| 129 | 1 |  |  | 1 |  | 374 | *$name = method ( $on ) { | 
|  | 1 |  |  |  |  | 11 |  | 
|  | 1 |  |  |  |  | 4 |  | 
|  | 1 |  |  |  |  | 2 |  | 
| 130 | 1 |  |  |  |  | 6 | $self->write_us( @bytes, $lastbyte + !!$on ); | 
| 131 | 16 |  |  |  |  | 80 | }; | 
| 132 |  |  |  |  |  |  | } | 
| 133 |  |  |  |  |  |  |  | 
| 134 | 16 |  |  |  |  | 33 | sub INT_COMMAND ( $name, $min, $max, @bytes ) | 
|  | 16 |  |  |  |  | 28 |  | 
|  | 16 |  |  |  |  | 28 |  | 
| 135 | 16 |  |  | 16 | 0 | 31 | { | 
|  | 16 |  |  |  |  | 28 |  | 
|  | 16 |  |  |  |  | 26 |  | 
| 136 | 16 |  |  |  |  | 53 | my $shortname = ( split m/_/, $name )[-1]; | 
| 137 |  |  |  |  |  |  |  | 
| 138 | 16 |  |  |  |  | 38 | my $lastbyte = pop @bytes; | 
| 139 |  |  |  |  |  |  |  | 
| 140 | 8 |  |  | 8 |  | 63 | no strict 'refs'; | 
|  | 8 |  |  |  |  | 16 |  | 
|  | 8 |  |  |  |  | 2487 |  | 
| 141 | 1 |  |  | 1 |  | 12927 | *$name = method ( $value ) { | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 2 |  | 
| 142 | 1 | 50 | 33 |  |  | 8 | $value >= $min and $value <= $max or | 
| 143 |  |  |  |  |  |  | croak "Invalid $shortname for ->$name"; | 
| 144 |  |  |  |  |  |  |  | 
| 145 | 1 |  |  |  |  | 5 | $self->write_us( @bytes, $lastbyte + $value ); | 
| 146 | 16 |  |  |  |  | 96 | }; | 
| 147 |  |  |  |  |  |  | } | 
| 148 |  |  |  |  |  |  |  | 
| 149 | 24 |  |  |  |  | 42 | sub ENUM_COMMAND ( $name, $values, @bytes ) | 
|  | 24 |  |  |  |  | 36 |  | 
| 150 | 24 |  |  | 24 | 0 | 38 | { | 
|  | 24 |  |  |  |  | 47 |  | 
|  | 24 |  |  |  |  | 37 |  | 
| 151 | 24 |  |  |  |  | 54 | my @values = @$values; | 
| 152 |  |  |  |  |  |  |  | 
| 153 | 24 |  |  |  |  | 60 | my $shortname = ( split m/_/, $name )[-1]; | 
| 154 |  |  |  |  |  |  |  | 
| 155 | 24 |  |  |  |  | 55 | my $lastbyte = pop @bytes; | 
| 156 |  |  |  |  |  |  |  | 
| 157 | 8 |  |  | 8 |  | 62 | no strict 'refs'; | 
|  | 8 |  |  |  |  | 18 |  | 
|  | 8 |  |  |  |  | 21110 |  | 
| 158 | 1 |  |  | 1 |  | 4024 | *$name = method ( $value ) { | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 2 |  | 
| 159 | 1 | 50 |  | 2 |  | 10 | defined( my $index = first { $values[$_] eq $value } 0 .. $#values ) or | 
|  | 2 |  |  |  |  | 9 |  | 
| 160 |  |  |  |  |  |  | croak "Invalid $shortname for ->$name"; | 
| 161 |  |  |  |  |  |  |  | 
| 162 | 1 |  |  |  |  | 6 | $self->write_us( @bytes, $lastbyte + $index ); | 
| 163 | 24 |  |  |  |  | 130 | }; | 
| 164 |  |  |  |  |  |  | } | 
| 165 |  |  |  |  |  |  |  | 
| 166 |  |  |  |  |  |  | =head2 cursor_left | 
| 167 |  |  |  |  |  |  |  | 
| 168 |  |  |  |  |  |  | =head2 cursor_right | 
| 169 |  |  |  |  |  |  |  | 
| 170 |  |  |  |  |  |  | =head2 cursor_home | 
| 171 |  |  |  |  |  |  |  | 
| 172 |  |  |  |  |  |  | await $chip->cursor_left; | 
| 173 |  |  |  |  |  |  | await $chip->cursor_right; | 
| 174 |  |  |  |  |  |  |  | 
| 175 |  |  |  |  |  |  | await $chip->cursor_linehome; | 
| 176 |  |  |  |  |  |  |  | 
| 177 |  |  |  |  |  |  | await $chip->cursor_home; | 
| 178 |  |  |  |  |  |  |  | 
| 179 |  |  |  |  |  |  | Move the cursor left or right one character position, to the beginning of the | 
| 180 |  |  |  |  |  |  | line, or to the home position (top left corner). | 
| 181 |  |  |  |  |  |  |  | 
| 182 |  |  |  |  |  |  | =cut | 
| 183 |  |  |  |  |  |  |  | 
| 184 | 0 |  |  | 0 | 1 | 0 | method cursor_left     { $self->write( "\x08" ) } | 
|  | 0 |  |  |  |  | 0 |  | 
| 185 | 0 |  |  | 0 | 1 | 0 | method cursor_right    { $self->write( "\x09" ) } | 
|  | 0 |  |  |  |  | 0 |  | 
| 186 | 0 |  |  | 0 | 0 | 0 | method cursor_linehome { $self->write( "\x0D" ) } | 
|  | 0 |  |  |  |  | 0 |  | 
| 187 | 0 |  |  | 0 | 1 | 0 | method cursor_home     { $self->write( "\x0B" ) } | 
|  | 0 |  |  |  |  | 0 |  | 
| 188 |  |  |  |  |  |  |  | 
| 189 |  |  |  |  |  |  | =head2 cursor_goto | 
| 190 |  |  |  |  |  |  |  | 
| 191 |  |  |  |  |  |  | await $chip->cursor_goto( $x, $y ); | 
| 192 |  |  |  |  |  |  |  | 
| 193 |  |  |  |  |  |  | Moves the cursor to the C<$x>'th column of the C<$y>'th line (zero-indexed). | 
| 194 |  |  |  |  |  |  |  | 
| 195 |  |  |  |  |  |  | =cut | 
| 196 |  |  |  |  |  |  |  | 
| 197 | 1 |  |  |  |  | 4 | method cursor_goto ( $x, $y ) | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 2 |  | 
| 198 | 1 |  |  | 1 | 1 | 4090 | { | 
| 199 |  |  |  |  |  |  | # TODO: Bounds-check $x, $y | 
| 200 |  |  |  |  |  |  |  | 
| 201 | 1 |  |  |  |  | 10 | $self->write( pack "C C S< S<", 0x1F, 0x24, $x, $y ); | 
| 202 |  |  |  |  |  |  | } | 
| 203 |  |  |  |  |  |  |  | 
| 204 |  |  |  |  |  |  | =head2 linefeed | 
| 205 |  |  |  |  |  |  |  | 
| 206 |  |  |  |  |  |  | await $chip->linefeed; | 
| 207 |  |  |  |  |  |  |  | 
| 208 |  |  |  |  |  |  | Move the cursor down to the next line. | 
| 209 |  |  |  |  |  |  |  | 
| 210 |  |  |  |  |  |  | =cut | 
| 211 |  |  |  |  |  |  |  | 
| 212 | 0 |  |  | 0 | 1 | 0 | method linefeed { $self->write( "\x0A" ) } | 
|  | 0 |  |  |  |  | 0 |  | 
| 213 |  |  |  |  |  |  |  | 
| 214 |  |  |  |  |  |  | =head2 clear | 
| 215 |  |  |  |  |  |  |  | 
| 216 |  |  |  |  |  |  | $chip->clear | 
| 217 |  |  |  |  |  |  |  | 
| 218 |  |  |  |  |  |  | Clear the display. | 
| 219 |  |  |  |  |  |  |  | 
| 220 |  |  |  |  |  |  | =cut | 
| 221 |  |  |  |  |  |  |  | 
| 222 | 3 |  |  | 3 | 1 | 36655 | method clear { $self->write( "\x0C" ) } | 
|  | 3 |  |  |  |  | 13 |  | 
| 223 |  |  |  |  |  |  |  | 
| 224 |  |  |  |  |  |  | =head2 select_window | 
| 225 |  |  |  |  |  |  |  | 
| 226 |  |  |  |  |  |  | await $chip->select_window( $win ); | 
| 227 |  |  |  |  |  |  |  | 
| 228 |  |  |  |  |  |  | Select the main window (when C<$win> is 0), or one of the four numbered | 
| 229 |  |  |  |  |  |  | sub-windows. | 
| 230 |  |  |  |  |  |  |  | 
| 231 |  |  |  |  |  |  | =cut | 
| 232 |  |  |  |  |  |  |  | 
| 233 |  |  |  |  |  |  | INT_COMMAND select_window => 0, 4, | 
| 234 |  |  |  |  |  |  | 0x10; | 
| 235 |  |  |  |  |  |  |  | 
| 236 |  |  |  |  |  |  | =head2 initialise | 
| 237 |  |  |  |  |  |  |  | 
| 238 |  |  |  |  |  |  | $chip->initialise | 
| 239 |  |  |  |  |  |  |  | 
| 240 |  |  |  |  |  |  | Reset all settings to their default values. | 
| 241 |  |  |  |  |  |  |  | 
| 242 |  |  |  |  |  |  | =cut | 
| 243 |  |  |  |  |  |  |  | 
| 244 | 0 |  |  | 0 | 1 | 0 | method initialise { $self->write( "\x1B\x40" ) } | 
|  | 0 |  |  |  |  | 0 |  | 
| 245 |  |  |  |  |  |  |  | 
| 246 |  |  |  |  |  |  | =head2 set_cursor_visible | 
| 247 |  |  |  |  |  |  |  | 
| 248 |  |  |  |  |  |  | await $chip->set_cursor_visible( $bool ); | 
| 249 |  |  |  |  |  |  |  | 
| 250 |  |  |  |  |  |  | Set whether the cursor is visible. | 
| 251 |  |  |  |  |  |  |  | 
| 252 |  |  |  |  |  |  | =cut | 
| 253 |  |  |  |  |  |  |  | 
| 254 |  |  |  |  |  |  | BOOL_COMMAND set_cursor_visible => | 
| 255 |  |  |  |  |  |  | 0x43, 0x00; | 
| 256 |  |  |  |  |  |  |  | 
| 257 |  |  |  |  |  |  | =head2 set_brightness | 
| 258 |  |  |  |  |  |  |  | 
| 259 |  |  |  |  |  |  | await $chip->set_brightness( $val ); | 
| 260 |  |  |  |  |  |  |  | 
| 261 |  |  |  |  |  |  | Set the display brightness, from 1 to 8. | 
| 262 |  |  |  |  |  |  |  | 
| 263 |  |  |  |  |  |  | =cut | 
| 264 |  |  |  |  |  |  |  | 
| 265 |  |  |  |  |  |  | INT_COMMAND set_brightness => 1, 8, | 
| 266 |  |  |  |  |  |  | 0x58, 0x00; | 
| 267 |  |  |  |  |  |  |  | 
| 268 |  |  |  |  |  |  | =head2 set_reverse | 
| 269 |  |  |  |  |  |  |  | 
| 270 |  |  |  |  |  |  | await $chip->set_reverse( $bool ); | 
| 271 |  |  |  |  |  |  |  | 
| 272 |  |  |  |  |  |  | Sets whether subsequent text will be rendered in "reverse video" (clear pixels | 
| 273 |  |  |  |  |  |  | on a set background) effect. | 
| 274 |  |  |  |  |  |  |  | 
| 275 |  |  |  |  |  |  | =cut | 
| 276 |  |  |  |  |  |  |  | 
| 277 |  |  |  |  |  |  | BOOL_COMMAND set_reverse => | 
| 278 |  |  |  |  |  |  | 0x72, 0x00; | 
| 279 |  |  |  |  |  |  |  | 
| 280 |  |  |  |  |  |  | =head2 set_write_mixture_display_mode | 
| 281 |  |  |  |  |  |  |  | 
| 282 |  |  |  |  |  |  | await $chip->set_write_mixture_display_mode( $mode ); | 
| 283 |  |  |  |  |  |  |  | 
| 284 |  |  |  |  |  |  | Set the combining mode for newly-added display content. C<$mode> must be one | 
| 285 |  |  |  |  |  |  | of | 
| 286 |  |  |  |  |  |  |  | 
| 287 |  |  |  |  |  |  | set or and xor | 
| 288 |  |  |  |  |  |  |  | 
| 289 |  |  |  |  |  |  | =cut | 
| 290 |  |  |  |  |  |  |  | 
| 291 |  |  |  |  |  |  | ENUM_COMMAND set_write_mixture_display_mode => [qw( set or and xor )], | 
| 292 |  |  |  |  |  |  | 0x77, 0x00; | 
| 293 |  |  |  |  |  |  |  | 
| 294 |  |  |  |  |  |  | =head2 set_font_size | 
| 295 |  |  |  |  |  |  |  | 
| 296 |  |  |  |  |  |  | await $chip->set_font_size( $size ); | 
| 297 |  |  |  |  |  |  |  | 
| 298 |  |  |  |  |  |  | Set the font size. C<$size> must be one of | 
| 299 |  |  |  |  |  |  |  | 
| 300 |  |  |  |  |  |  | 5x7 8x16 | 
| 301 |  |  |  |  |  |  |  | 
| 302 |  |  |  |  |  |  | =cut | 
| 303 |  |  |  |  |  |  |  | 
| 304 |  |  |  |  |  |  | ENUM_COMMAND set_font_size => [qw( 5x7 8x16 )], | 
| 305 |  |  |  |  |  |  | 0x28, 0x67, 0x01, 0x01; | 
| 306 |  |  |  |  |  |  |  | 
| 307 |  |  |  |  |  |  | =head2 set_font_width | 
| 308 |  |  |  |  |  |  |  | 
| 309 |  |  |  |  |  |  | await $chip->set_font_width( $width ); | 
| 310 |  |  |  |  |  |  |  | 
| 311 |  |  |  |  |  |  | Set the font width. C<$width> must be one of | 
| 312 |  |  |  |  |  |  |  | 
| 313 |  |  |  |  |  |  | fixed fixed2 prop prop2 | 
| 314 |  |  |  |  |  |  |  | 
| 315 |  |  |  |  |  |  | =cut | 
| 316 |  |  |  |  |  |  |  | 
| 317 |  |  |  |  |  |  | ENUM_COMMAND set_font_width => [qw( fixed fixed2 prop prop2 )], | 
| 318 |  |  |  |  |  |  | 0x28, 0x67, 0x03, 0x00; | 
| 319 |  |  |  |  |  |  |  | 
| 320 |  |  |  |  |  |  | =head2 set_font_magnification | 
| 321 |  |  |  |  |  |  |  | 
| 322 |  |  |  |  |  |  | await $chip->set_font_magnification( $xscale, $yscale ); | 
| 323 |  |  |  |  |  |  |  | 
| 324 |  |  |  |  |  |  | Set the font scaling factor. C<$xscale> must be between 1 to 4, and | 
| 325 |  |  |  |  |  |  | C<$yscale> must be 1 or 2. | 
| 326 |  |  |  |  |  |  |  | 
| 327 |  |  |  |  |  |  | =cut | 
| 328 |  |  |  |  |  |  |  | 
| 329 | 0 |  |  |  |  | 0 | method set_font_magnification ( $x, $y ) | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 330 | 0 |  |  | 0 | 1 | 0 | { | 
| 331 | 0 | 0 | 0 |  |  | 0 | $x >= 1 and $x <= 4 or croak "Invalid x scale"; | 
| 332 | 0 | 0 | 0 |  |  | 0 | $y >= 1 and $y <= 2 or croak "Invalid y scale"; | 
| 333 |  |  |  |  |  |  |  | 
| 334 | 0 |  |  |  |  | 0 | $self->write_us( 0x28, 0x67, 0x40, $x, $y ); | 
| 335 |  |  |  |  |  |  | } | 
| 336 |  |  |  |  |  |  |  | 
| 337 | 1 |  |  |  |  | 2 | method _realtime_image_display ( $width, $height, $bytes ) | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 2 |  | 
| 338 | 1 |  |  | 1 |  | 3 | { | 
| 339 | 1 |  |  |  |  | 13 | $self->write( "\x1F\x28\x66\x11" . pack "S< S< C a*", | 
| 340 |  |  |  |  |  |  | $width, $height, 1, $bytes, | 
| 341 |  |  |  |  |  |  | ); | 
| 342 |  |  |  |  |  |  | } | 
| 343 |  |  |  |  |  |  |  | 
| 344 |  |  |  |  |  |  | =head2 realtime_image_display_columns | 
| 345 |  |  |  |  |  |  |  | 
| 346 |  |  |  |  |  |  | await $chip->realtime_image_display_columns( @columns ); | 
| 347 |  |  |  |  |  |  |  | 
| 348 |  |  |  |  |  |  | Sends a bitmapped image to the display, at the cursor position. The cursor is | 
| 349 |  |  |  |  |  |  | not moved. | 
| 350 |  |  |  |  |  |  |  | 
| 351 |  |  |  |  |  |  | C<@columns> should be a list of strings of equal length, containing bytes of | 
| 352 |  |  |  |  |  |  | pixel data to represent each vertical column of the image content. | 
| 353 |  |  |  |  |  |  |  | 
| 354 |  |  |  |  |  |  | =cut | 
| 355 |  |  |  |  |  |  |  | 
| 356 | 1 |  |  |  |  | 3 | method realtime_image_display_columns ( @columns ) | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 2 |  | 
| 357 | 1 |  |  | 1 | 1 | 297 | { | 
| 358 | 1 | 50 |  |  |  | 4 | @columns or croak "Expected at least 1 column"; | 
| 359 | 1 |  |  |  |  | 4 | my $height = length $columns[0]; | 
| 360 | 1 |  | 33 |  |  | 18 | $height == length $_ or croak "Expected all columns of equal length" for @columns[1..$#columns]; | 
| 361 |  |  |  |  |  |  |  | 
| 362 | 1 |  |  |  |  | 5 | my $bytes = join "", @columns; | 
| 363 |  |  |  |  |  |  |  | 
| 364 | 1 |  |  |  |  | 5 | $self->_realtime_image_display( scalar @columns, $height, $bytes ); | 
| 365 |  |  |  |  |  |  | } | 
| 366 |  |  |  |  |  |  |  | 
| 367 | 0 |  |  |  |  | 0 | method realtime_image_display_lines ( @lines ) | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 368 | 0 |  |  | 0 | 0 | 0 | { | 
| 369 | 0 | 0 |  |  |  | 0 | @lines or croak "Expected at least 1 line"; | 
| 370 | 0 |  |  |  |  | 0 | my $width = length $lines[0]; | 
| 371 | 0 |  | 0 |  |  | 0 | $width == length $_ or croak "Expected all lines of equal length" for @lines[1..$#lines]; | 
| 372 |  |  |  |  |  |  |  | 
| 373 |  |  |  |  |  |  | # Restripe the data in vertical strips | 
| 374 |  |  |  |  |  |  | my $bytes = join "", map { | 
| 375 | 0 |  |  |  |  | 0 | my $col = $_; | 
|  | 0 |  |  |  |  | 0 |  | 
| 376 | 0 |  |  |  |  | 0 | map { substr( $lines[$_], $col, 1 ) } 0 .. $#lines | 
|  | 0 |  |  |  |  | 0 |  | 
| 377 |  |  |  |  |  |  | } 0 .. $width-1; | 
| 378 |  |  |  |  |  |  |  | 
| 379 | 0 |  |  |  |  | 0 | $self->_realtime_image_display( $width, scalar @lines, $bytes ); | 
| 380 |  |  |  |  |  |  | } | 
| 381 |  |  |  |  |  |  |  | 
| 382 |  |  |  |  |  |  | =head2 set_gpio_direction | 
| 383 |  |  |  |  |  |  |  | 
| 384 |  |  |  |  |  |  | await $chip->set_gpio_direction( $dir ); | 
| 385 |  |  |  |  |  |  |  | 
| 386 |  |  |  |  |  |  | Configure the GPIO pins for input or output. C<$dir> is bitmask of four bits. | 
| 387 |  |  |  |  |  |  | Low bits correspond to input, high bits to output. | 
| 388 |  |  |  |  |  |  |  | 
| 389 |  |  |  |  |  |  | =cut | 
| 390 |  |  |  |  |  |  |  | 
| 391 | 1 |  |  |  |  | 2 | async method set_gpio_direction ( $dir ) | 
|  | 1 |  |  |  |  | 4 |  | 
|  | 1 |  |  |  |  | 2 |  | 
| 392 | 1 |  |  |  |  | 3 | { | 
| 393 | 1 |  |  |  |  | 15 | await $self->write_us( 0x28, 0x70, 0x01, 0x00, $dir & 0x0F ); | 
| 394 | 1 |  |  | 1 | 1 | 304 | } | 
| 395 |  |  |  |  |  |  |  | 
| 396 |  |  |  |  |  |  | =head2 set_gpio_output | 
| 397 |  |  |  |  |  |  |  | 
| 398 |  |  |  |  |  |  | await $chip->set_gpio_output( $value ); | 
| 399 |  |  |  |  |  |  |  | 
| 400 |  |  |  |  |  |  | Write the value to the GPIO pins. | 
| 401 |  |  |  |  |  |  |  | 
| 402 |  |  |  |  |  |  | =cut | 
| 403 |  |  |  |  |  |  |  | 
| 404 | 1 |  |  |  |  | 3 | async method write_gpio ( $value ) | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 2 |  | 
| 405 | 1 |  |  |  |  | 6 | { | 
| 406 | 1 |  |  |  |  | 6 | await $self->write_us( 0x28, 0x70, 0x10, 0x00, $value & 0x0F ); | 
| 407 | 1 |  |  | 1 | 0 | 12656 | } | 
| 408 |  |  |  |  |  |  |  | 
| 409 |  |  |  |  |  |  | =head2 read_gpio | 
| 410 |  |  |  |  |  |  |  | 
| 411 |  |  |  |  |  |  | $value = await $chip->read_gpio; | 
| 412 |  |  |  |  |  |  |  | 
| 413 |  |  |  |  |  |  | Returns the current state of the GPIO pins. | 
| 414 |  |  |  |  |  |  |  | 
| 415 |  |  |  |  |  |  | =cut | 
| 416 |  |  |  |  |  |  |  | 
| 417 |  |  |  |  |  |  | async method read_gpio | 
| 418 | 1 |  |  |  |  | 4 | { | 
| 419 | 1 |  |  |  |  | 4 | await $self->write_us( 0x28, 0x70, 0x20, 0x00 ); | 
| 420 | 1 |  |  |  |  | 1426 | my ( $header, $id1, $id2, $value ) = unpack "C4", await $self->read( 4 ); | 
| 421 |  |  |  |  |  |  |  | 
| 422 | 1 | 50 | 33 |  |  | 1396 | croak "Expected 0x28 0x70 0x20" unless $header == 0x28 and | 
|  |  |  | 33 |  |  |  |  | 
| 423 |  |  |  |  |  |  | $id1 == 0x70 and $id2 == 0x20; | 
| 424 |  |  |  |  |  |  |  | 
| 425 | 1 |  |  |  |  | 5 | return $value; | 
| 426 | 1 |  |  | 1 | 1 | 4023 | } | 
| 427 |  |  |  |  |  |  |  | 
| 428 |  |  |  |  |  |  | =head2 read_touchswitches | 
| 429 |  |  |  |  |  |  |  | 
| 430 |  |  |  |  |  |  | $switches = await $chip->read_touchswitches; | 
| 431 |  |  |  |  |  |  |  | 
| 432 |  |  |  |  |  |  | Reads the status of the panel touch switches. Returns a hash reference whose | 
| 433 |  |  |  |  |  |  | keys are the names of the touch areas (C, C, ...) and values are | 
| 434 |  |  |  |  |  |  | booleans indicating whether that area currently detects a touch. | 
| 435 |  |  |  |  |  |  |  | 
| 436 |  |  |  |  |  |  | =cut | 
| 437 |  |  |  |  |  |  |  | 
| 438 |  |  |  |  |  |  | async method read_touchswitches | 
| 439 | 1 |  |  |  |  | 3 | { | 
| 440 | 1 |  |  |  |  | 5 | await $self->write( "\x1F\x4B\x10" ); | 
| 441 |  |  |  |  |  |  |  | 
| 442 | 1 |  |  |  |  | 9087 | my ( $header, $len, $switches ) = unpack "C C S>", await $self->read( 4 ); | 
| 443 | 1 | 50 |  |  |  | 1439 | croak sprintf "Expected header = 0x10; got 0x%02X", $header if $header != 0x10; | 
| 444 | 1 | 50 |  |  |  | 3 | croak "Expected length=2, got $len" if $len != 2; | 
| 445 |  |  |  |  |  |  |  | 
| 446 |  |  |  |  |  |  | return { | 
| 447 | 1 |  |  |  |  | 32 | map +("SW$_", $switches & ( 2 ** ( $_-1 ) )), 1 .. 16 | 
| 448 |  |  |  |  |  |  | }; | 
| 449 | 1 |  |  | 1 | 1 | 348 | } | 
| 450 |  |  |  |  |  |  |  | 
| 451 |  |  |  |  |  |  | # Interface helpers | 
| 452 |  |  |  |  |  |  |  | 
| 453 |  |  |  |  |  |  | class Device::Chip::NoritakeGU_D::_Iface::UART { | 
| 454 | 8 |  |  | 8 |  | 1105 | use constant DEFAULT_BAUDRATE => 38400; | 
|  | 8 |  |  |  |  | 21 |  | 
|  | 8 |  |  |  |  | 5022 |  | 
| 455 |  |  |  |  |  |  |  | 
| 456 |  |  |  |  |  |  | field $_baudrate; | 
| 457 |  |  |  |  |  |  |  | 
| 458 | 5 |  |  |  |  | 12 | method mountopts ( $params ) | 
|  | 5 |  |  |  |  | 10 |  | 
|  | 5 |  |  |  |  | 10 |  | 
| 459 | 5 |  |  | 5 |  | 15 | { | 
| 460 | 5 |  | 50 |  |  | 35 | $_baudrate = delete $params->{baudrate} // DEFAULT_BAUDRATE; | 
| 461 |  |  |  |  |  |  | } | 
| 462 |  |  |  |  |  |  |  | 
| 463 |  |  |  |  |  |  | method options | 
| 464 | 5 |  |  | 5 |  | 15 | { | 
| 465 |  |  |  |  |  |  | return ( | 
| 466 | 5 |  |  |  |  | 29 | baudrate => $_baudrate, | 
| 467 |  |  |  |  |  |  | ); | 
| 468 |  |  |  |  |  |  | } | 
| 469 |  |  |  |  |  |  |  | 
| 470 | 11 |  |  |  |  | 20 | async method write ( $chip, $bytes ) | 
|  | 11 |  |  |  |  | 23 |  | 
|  | 11 |  |  |  |  | 21 |  | 
|  | 11 |  |  |  |  | 17 |  | 
| 471 | 11 |  |  |  |  | 31 | { | 
| 472 | 11 |  |  |  |  | 42 | await $chip->protocol->write( $bytes ); | 
| 473 | 11 |  |  | 11 |  | 25 | } | 
| 474 |  |  |  |  |  |  |  | 
| 475 | 3 |  |  |  |  | 7 | async method read ( $chip, $len ) | 
|  | 3 |  |  |  |  | 7 |  | 
|  | 3 |  |  |  |  | 7 |  | 
|  | 3 |  |  |  |  | 6 |  | 
| 476 | 3 |  |  |  |  | 12 | { | 
| 477 | 3 |  |  |  |  | 33 | return await $chip->protocol->read( $len ); | 
| 478 | 3 |  |  | 3 |  | 51 | } | 
| 479 |  |  |  |  |  |  | } | 
| 480 |  |  |  |  |  |  |  | 
| 481 |  |  |  |  |  |  | class Device::Chip::NoritakeGU_D::_Iface::I2C { | 
| 482 | 8 |  |  | 8 |  | 973 | use constant DEFAULT_ADDR => 0x50; | 
|  | 8 |  |  |  |  | 20 |  | 
|  | 8 |  |  |  |  | 4503 |  | 
| 483 |  |  |  |  |  |  |  | 
| 484 |  |  |  |  |  |  | field $_addr; | 
| 485 |  |  |  |  |  |  |  | 
| 486 | 1 |  |  |  |  | 2 | method mountopts ( $params ) | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 2 |  | 
| 487 | 1 |  |  | 1 |  | 2 | { | 
| 488 | 1 |  | 50 |  |  | 9 | $_addr = delete $params->{addr} // DEFAULT_ADDR; | 
| 489 |  |  |  |  |  |  | } | 
| 490 |  |  |  |  |  |  |  | 
| 491 |  |  |  |  |  |  | method options | 
| 492 | 1 |  |  | 1 |  | 3 | { | 
| 493 |  |  |  |  |  |  | return ( | 
| 494 | 1 |  |  |  |  | 5 | addr => $_addr, | 
| 495 |  |  |  |  |  |  | ); | 
| 496 |  |  |  |  |  |  | } | 
| 497 |  |  |  |  |  |  |  | 
| 498 | 2 |  |  |  |  | 4 | async method write ( $chip, $bytes ) | 
|  | 2 |  |  |  |  | 2 |  | 
|  | 2 |  |  |  |  | 5 |  | 
|  | 2 |  |  |  |  | 11 |  | 
| 499 | 2 |  |  |  |  | 5 | { | 
| 500 | 2 |  |  |  |  | 9 | await $chip->protocol->write( $bytes ); | 
| 501 | 2 |  |  | 2 |  | 4 | } | 
| 502 |  |  |  |  |  |  |  | 
| 503 | 1 |  |  |  |  | 2 | async method read ( $chip, $len ) | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 1 |  | 
| 504 | 1 |  |  |  |  | 2 | { | 
| 505 | 1 |  |  |  |  | 6 | return await $chip->protocol->read( $len ); | 
| 506 | 1 |  |  | 1 |  | 3 | } | 
| 507 |  |  |  |  |  |  | } | 
| 508 |  |  |  |  |  |  |  | 
| 509 |  |  |  |  |  |  | class Device::Chip::NoritakeGU_D::_Iface::SPI { | 
| 510 | 1 |  |  | 1 |  | 2 | method mountopts ( $ ) {} | 
|  | 1 |  |  |  |  | 2 |  | 
| 511 |  |  |  |  |  |  |  | 
| 512 |  |  |  |  |  |  | method options | 
| 513 | 1 |  |  | 1 |  | 3 | { | 
| 514 |  |  |  |  |  |  | return ( | 
| 515 | 1 |  |  |  |  | 6 | mode => 0, | 
| 516 |  |  |  |  |  |  | # max_bitrate => 2E6, # min clock period 500ns | 
| 517 |  |  |  |  |  |  | # Need to slow the bitrate down in order to generate inter-word gaps | 
| 518 |  |  |  |  |  |  | max_bitrate => 500E3, | 
| 519 |  |  |  |  |  |  | ); | 
| 520 |  |  |  |  |  |  | } | 
| 521 |  |  |  |  |  |  |  | 
| 522 | 2 |  |  |  |  | 3 | async method write ( $chip, $bytes ) | 
|  | 2 |  |  |  |  | 4 |  | 
|  | 2 |  |  |  |  | 4 |  | 
|  | 2 |  |  |  |  | 2 |  | 
| 523 | 2 |  |  |  |  | 4 | { | 
| 524 | 2 |  |  |  |  | 7 | await $chip->protocol->write( "\x44" . $bytes ); | 
| 525 | 2 |  |  | 2 |  | 4 | } | 
| 526 |  |  |  |  |  |  |  | 
| 527 | 1 |  |  |  |  | 3 | async method read ( $chip, $len ) | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 1 |  | 
| 528 | 1 |  |  |  |  | 2 | { | 
| 529 |  |  |  |  |  |  | # TODO: | 
| 530 |  |  |  |  |  |  | #   The datasheet says that after you write a 0x58 byte, the very next byte | 
| 531 |  |  |  |  |  |  | #   you get back will be the status. Experimental testing shows you get an | 
| 532 |  |  |  |  |  |  | #   echo of the 0x58 first, then status. | 
| 533 |  |  |  |  |  |  |  | 
| 534 | 1 |  |  |  |  | 4 | my $status = unpack "x C", await $chip->protocol->write_then_read( "\x58", 2 ); | 
| 535 |  |  |  |  |  |  |  | 
| 536 |  |  |  |  |  |  | #   The datasheet says that after you write a 0x54 byte, you'll immediately | 
| 537 |  |  |  |  |  |  | #   get 0x00 then the data. Experimental testing suggests that you get an | 
| 538 |  |  |  |  |  |  | #   echo of the 0x54 byte first, then 0x00, then the data. | 
| 539 |  |  |  |  |  |  |  | 
| 540 | 1 |  |  |  |  | 1257 | my $bytes = await $chip->protocol->write_then_read( "\x54", ( $status & 0x1F ) + 2 ); | 
| 541 |  |  |  |  |  |  |  | 
| 542 | 1 |  |  |  |  | 1258 | return substr $bytes, 2; | 
| 543 | 1 |  |  | 1 |  | 3 | } | 
| 544 |  |  |  |  |  |  | } | 
| 545 |  |  |  |  |  |  |  | 
| 546 |  |  |  |  |  |  | =head1 AUTHOR | 
| 547 |  |  |  |  |  |  |  | 
| 548 |  |  |  |  |  |  | Paul Evans | 
| 549 |  |  |  |  |  |  |  | 
| 550 |  |  |  |  |  |  | =cut | 
| 551 |  |  |  |  |  |  |  | 
| 552 |  |  |  |  |  |  | 0x55AA; |