/* ***************************************************************************** * usage/getscreen.c -- receive the streamed screen from the calculator. * Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey * * 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 . * ************************************************************************** */ #include #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); }