163 lines
4.7 KiB
C
163 lines
4.7 KiB
C
/* *****************************************************************************
|
|
* usage/getscreen.c -- receive the streamed screen from the calculator.
|
|
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
|
|
*
|
|
* This file is part of libp7.
|
|
* libp7 is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation; either version 3.0 of the License,
|
|
* or (at your option) any later version.
|
|
*
|
|
* libp7 is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
* See the GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with libp7; if not, see <http://www.gnu.org/licenses/>.
|
|
* ************************************************************************** */
|
|
#include <libp7/internals.h>
|
|
#define makepixel(R, G, B) (((R) << 16) | ((G) << 8) | (B))
|
|
|
|
/**
|
|
* p7_getscreen_adapt:
|
|
* Adapts the pixels from the received VRAM.
|
|
*
|
|
* @arg pixels the pixels matrix
|
|
* @arg w pointer to the width var
|
|
* @arg h pointer to the height var
|
|
* @arg scrtype the VRAM type
|
|
* @arg vram the VRAM data
|
|
*/
|
|
|
|
static void p7_getscreen_adapt(uint32_t **pixels, p7_packet_t *resp)
|
|
{
|
|
uint8_t *vram = resp->p7_seven_packet_vram; int msk;
|
|
uint32_t prizm_gray_colors[] = {0xFFFFFF, 0xAAAAAA, 0x777777, 0x000000};
|
|
|
|
switch (resp->p7_seven_packet_pictype) {
|
|
/* monochrome */
|
|
case p7_pictype_1bit:
|
|
msk = 0x80;
|
|
for (unsigned int y = 0; y < resp->p7_seven_packet_height; y++)
|
|
for (unsigned int x = 0; x < resp->p7_seven_packet_width; x++) {
|
|
/* get pixel */
|
|
pixels[y][x] = (*vram & msk) ? 0x000000 : 0xFFFFFF;
|
|
|
|
/* go to next bit */
|
|
vram += msk & 1;
|
|
msk = (msk >> 1) | ((msk & 1) << 7);
|
|
}
|
|
break;
|
|
|
|
/* 2-bit (Prizm's encoding) */
|
|
case p7_pictype_2bit:
|
|
msk = 0x80; uint8_t *v2 = &vram[resp->p7_seven_packet_height
|
|
* resp->p7_seven_packet_width / 8];
|
|
for (unsigned int y = 0; y < resp->p7_seven_packet_height; y++)
|
|
for (unsigned int x = 0; x < resp->p7_seven_packet_width; x++) {
|
|
/* get pixel */
|
|
uint32_t val = (!!(*vram & msk) << 1) | !!(*v2 & msk);
|
|
pixels[y][x] = prizm_gray_colors[val];
|
|
|
|
/* go to next */
|
|
vram += msk & 1; v2 += msk & 1;
|
|
msk = (msk >> 1) | ((msk & 1) << 7);
|
|
}
|
|
break;
|
|
|
|
/* 3-bit */
|
|
case p7_pictype_3bit:
|
|
msk = 0xF0;
|
|
for (unsigned int y = resp->p7_seven_packet_height - 1;
|
|
y != (unsigned int)-1; y--)
|
|
for (unsigned int x = resp->p7_seven_packet_width - 1;
|
|
x != (unsigned int)-1; x--) {
|
|
/* get pixel */
|
|
uint32_t val = *vram & msk; val = val | (val >> 4);
|
|
uint32_t px = 0;
|
|
if (px & 8) px |= 0xFF0000;
|
|
if (px & 4) px |= 0x00FF00;
|
|
if (px & 2) px |= 0x0000FF;
|
|
pixels[y][x] = px;
|
|
|
|
/* go to next */
|
|
vram += msk & 1;
|
|
msk = ~msk & 0xFF;
|
|
}
|
|
break;
|
|
|
|
/* 16-bit */
|
|
case p7_pictype_16bit:
|
|
for (unsigned int y = 0; y < resp->p7_seven_packet_height; y++)
|
|
for (unsigned int x = 0; x < resp->p7_seven_packet_width; x++) {
|
|
/* get pixel */
|
|
uint32_t o = vram[0], t = vram[1];
|
|
pixels[y][x] = (o >> 3) << (16 + 3);
|
|
pixels[y][x] |= (((o & 7) << 3) | (t >> 5)) << (8 + 2);
|
|
pixels[y][x] |= (t & 31) << (0 + 3);
|
|
|
|
/* go to next */
|
|
vram += 2;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* p7_getscreen:
|
|
* Get the screen.
|
|
*
|
|
* @arg handle the libp7 handle
|
|
* @arg callback the main callback for the function.
|
|
* for each correctly received frame, the function will
|
|
* be called with the dimensions (w, h) and the pixels
|
|
* matrix.
|
|
* if it returns 0, the function stops.
|
|
* @return if it worked
|
|
*/
|
|
|
|
p7_define_ufunc(p7_getscreen, p7_attrs_getscreen,
|
|
p7_handle_t *handle, p7_screenfunc_t *callback)
|
|
{
|
|
int err;
|
|
/* make checks */
|
|
chk_handle(handle);
|
|
chk_seven(handle);
|
|
chk_passive(handle);
|
|
|
|
/* allocate pixels */
|
|
uint32_t **pixels = malloc(sizeof(uint32_t*) * MAX_VRAM_HEIGHT
|
|
+ sizeof(uint32_t) * MAX_VRAM_WIDTH * MAX_VRAM_HEIGHT);
|
|
if (!pixels) return (p7_error_alloc);
|
|
|
|
/* prepare pixels */
|
|
int y = MAX_VRAM_HEIGHT;
|
|
uint32_t *base = (uint32_t*)(pixels + MAX_VRAM_HEIGHT);
|
|
while (y--) pixels[y] = base + y * MAX_VRAM_WIDTH;
|
|
|
|
/* main loop */
|
|
handle->_flags |= p7_intflag_adjscreen;
|
|
while (1) {
|
|
/* get packet */
|
|
if ((err = p7_seven_recv(handle, 0)))
|
|
return (err);
|
|
if (response.p7_seven_packet_type != p7_seven_type_ohp)
|
|
return (p7_error_unknown);
|
|
|
|
/* convert */
|
|
if (response.p7_seven_packet_pictype) {
|
|
p7_getscreen_adapt(pixels, &response);
|
|
|
|
/* then call back the callback */
|
|
if (!(*callback)(response.p7_seven_packet_width,
|
|
response.p7_seven_packet_height, pixels))
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* stop */
|
|
free(pixels);
|
|
return (0);
|
|
}
|