Merge pull request #1034 from schneider42/rad1o-ui-cleanup

rad1o UI support
This commit is contained in:
Michael Ossmann
2022-02-07 23:25:01 -07:00
committed by GitHub
22 changed files with 4544 additions and 46 deletions

View File

@ -43,6 +43,7 @@ void hackrf_ui_set_first_if_frequency_null(const uint64_t frequency) { UNUSED(fr
void hackrf_ui_set_filter_null(const rf_path_filter_t filter) { UNUSED(filter); } void hackrf_ui_set_filter_null(const rf_path_filter_t filter) { UNUSED(filter); }
void hackrf_ui_set_antenna_bias_null(bool antenna_bias) { UNUSED(antenna_bias); } void hackrf_ui_set_antenna_bias_null(bool antenna_bias) { UNUSED(antenna_bias); }
void hackrf_ui_set_clock_source_null(clock_source_t source) { UNUSED(source); } void hackrf_ui_set_clock_source_null(clock_source_t source) { UNUSED(source); }
void hackrf_ui_set_transceiver_mode_null(transceiver_mode_t mode) { UNUSED(mode); }
bool hackrf_ui_operacake_gpio_compatible_null(void) { return true; } bool hackrf_ui_operacake_gpio_compatible_null(void) { return true; }
/* Null UI function table, used if there's no hardware UI detected. Eliminates the /* Null UI function table, used if there's no hardware UI detected. Eliminates the
@ -63,6 +64,7 @@ static const hackrf_ui_t hackrf_ui_null = {
&hackrf_ui_set_filter_null, &hackrf_ui_set_filter_null,
&hackrf_ui_set_antenna_bias_null, &hackrf_ui_set_antenna_bias_null,
&hackrf_ui_set_clock_source_null, &hackrf_ui_set_clock_source_null,
&hackrf_ui_set_transceiver_mode_null,
&hackrf_ui_operacake_gpio_compatible_null &hackrf_ui_operacake_gpio_compatible_null
}; };

View File

@ -39,6 +39,7 @@ typedef void (*hackrf_ui_set_first_if_frequency_fn)(const uint64_t frequency);
typedef void (*hackrf_ui_set_filter_fn)(const rf_path_filter_t filter); typedef void (*hackrf_ui_set_filter_fn)(const rf_path_filter_t filter);
typedef void (*hackrf_ui_set_antenna_bias_fn)(bool antenna_bias); typedef void (*hackrf_ui_set_antenna_bias_fn)(bool antenna_bias);
typedef void (*hackrf_ui_set_clock_source_fn)(clock_source_t source); typedef void (*hackrf_ui_set_clock_source_fn)(clock_source_t source);
typedef void (*hackrf_ui_set_transceiver_mode_fn)(transceiver_mode_t mode);
typedef bool (*hackrf_ui_operacake_gpio_compatible_fn)(void); typedef bool (*hackrf_ui_operacake_gpio_compatible_fn)(void);
typedef struct { typedef struct {
@ -56,6 +57,7 @@ typedef struct {
hackrf_ui_set_filter_fn set_filter; hackrf_ui_set_filter_fn set_filter;
hackrf_ui_set_antenna_bias_fn set_antenna_bias; hackrf_ui_set_antenna_bias_fn set_antenna_bias;
hackrf_ui_set_clock_source_fn set_clock_source; hackrf_ui_set_clock_source_fn set_clock_source;
hackrf_ui_set_transceiver_mode_fn set_transceiver_mode;
hackrf_ui_operacake_gpio_compatible_fn operacake_gpio_compatible; hackrf_ui_operacake_gpio_compatible_fn operacake_gpio_compatible;
} hackrf_ui_t; } hackrf_ui_t;

View File

@ -0,0 +1,127 @@
#include "fonts.h"
#include "render.h"
#include <stdint.h>
// Local function: Get next nibble.
static int ctr = 0; // offset for next nibble
static int hilo = 0; // 0= high nibble next, 1=low nibble next
static const uint8_t *data;
#define MAXCHR (30 * 20)
static uint8_t charBuf[MAXCHR];
// Get next nibble
static uint8_t gnn()
{
static uint8_t byte;
uint8_t val;
if (hilo == 1)
ctr++;
hilo = 1 - hilo;
if (hilo == 1) {
byte = data[ctr];
val = byte >> 4;
} else {
val = byte & 0x0f;
};
return val;
}
// Local function: Unpack "long run".
static int upl(int off)
{
int retval;
while ((retval = gnn()) == 0) {
off++;
};
while (off-- > 0) {
retval = retval << 4;
retval += gnn();
};
return retval;
}
uint8_t *rad1o_pk_decode(const uint8_t *ldata, int *len)
{
ctr = 0;
hilo = 0;
data = ldata;
int length = *len; // Length of character bytestream
int height; // Height of character in bytes
int hoff; // bit position for non-integer heights
uint8_t *bufptr = charBuf; // Output buffer for decoded character
height = (rad1o_getFontHeight() - 1) / 8 + 1;
hoff = rad1o_getFontHeight() % 8;
#define DYN (12) // Decoder parameter: Fixed value for now.
int repeat = 0; // Decoder internal: repeat colum?
int curbit = 0; // Decoder internal: current bit (1 or 0)
int pos = 0; // Decoder internal: current bit position (0..7)
int nyb; // Decoder internal: current nibble / value
if (data[ctr] >> 4 == 14) { // Char starts with 1-bits.
gnn();
curbit = 1;
};
while (ctr < length) { /* Iterate the whole input stream */
/* Get next encoded nibble and decode */
nyb = gnn();
if (nyb == 15) {
repeat++;
continue;
} else if (nyb == 14) {
nyb = upl(0);
nyb += 1;
repeat += nyb;
continue;
} else if (nyb > DYN) {
nyb = (16 * (nyb - DYN - 1)) + gnn() + DYN + 1;
} else if (nyb == 0) {
nyb = upl(1);
nyb += (16 * (13 - DYN) + DYN) - 16;
};
/* Generate & output bits */
while (nyb-- > 0) {
if (pos == 0) // Clear each byte before we start.
*bufptr = 0;
if (curbit == 1) {
*bufptr |= 1 << (7 - pos);
};
pos++;
if (((bufptr - charBuf) % height) == (height - 1) &&
(pos == hoff)) {
// Finish incomplete last byte per column
pos = 8;
};
if (pos == 8) {
bufptr++;
if ((bufptr - charBuf) % height ==
0) { // End of column?
while (repeat > 0) {
for (int y = 0; y < height;
y++) {
bufptr[0] =
bufptr[-height];
bufptr++;
};
repeat--;
};
};
pos = 0;
};
};
curbit = 1 - curbit;
};
*len = (bufptr - charBuf) / height; // return size of output buffer.
return charBuf;
}

View File

@ -0,0 +1,8 @@
#ifndef __RAD1O_DECODER_H__
#define __RAD1O_DECODER_H__
#include <stdint.h>
uint8_t *rad1o_pk_decode(const uint8_t *data, int *len);
#endif

View File

@ -0,0 +1,180 @@
#include "display.h"
#include "gpio_lpc.h"
#include "hackrf_core.h"
#include <libopencm3/lpc43xx/scu.h>
#include <libopencm3/lpc43xx/ssp.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
static void delayms(const uint32_t milliseconds)
{
/* NOTE: Naively assumes 204 MHz instruction cycle clock and five instructions per count */
delay(milliseconds * 40800);
}
static struct gpio_t gpio_lcd_cs = GPIO(4, 12); /* P9_0 */
static struct gpio_t gpio_lcd_bl_en = GPIO(0, 8); /* P1_1 */
static struct gpio_t gpio_lcd_reset = GPIO(5, 17); /* P9_4 */
/**************************************************************************/
/* Utility routines to manage nokia display */
/**************************************************************************/
static void rotate(void);
static uint8_t lcdBuffer[RESX * RESY];
static bool isTurned;
static void select()
{
/*
* The LCD requires 9-Bit frames
* Freq = PCLK / (CPSDVSR * [SCR+1])
* We want 120ns / bit -> 8.3 MHz.
* SPI1 BASE CLOCK is expected to be 204 MHz.
* 204 MHz / ( 12 * (1 + 1)) = 8.5 MHz
*
* Set CPSDVSR = 12
*/
uint8_t serial_clock_rate = 1;
uint8_t clock_prescale_rate = 12;
ssp_init(LCD_SSP, SSP_DATA_9BITS, SSP_FRAME_SPI, SSP_CPOL_0_CPHA_0,
serial_clock_rate, clock_prescale_rate, SSP_MODE_NORMAL,
SSP_MASTER, SSP_SLAVE_OUT_ENABLE);
gpio_clear(&gpio_lcd_cs);
}
static void deselect()
{
gpio_set(&gpio_lcd_cs);
}
static void write(uint8_t cd, uint8_t data)
{
uint16_t frame = 0x0;
frame = cd << 8;
frame |= data;
ssp_transfer(LCD_SSP, frame);
}
void rad1o_lcdInit(void)
{
gpio_output(&gpio_lcd_bl_en);
gpio_output(&gpio_lcd_reset);
gpio_output(&gpio_lcd_cs);
/* prepare SPI */
SETUPpin(LCD_DI);
SETUPpin(LCD_SCK);
// Reset the display
gpio_clear(&gpio_lcd_reset);
delayms(100);
gpio_set(&gpio_lcd_reset);
delayms(100);
select();
/* The controller is a PCF8833 - documentation can be found online. */
static uint8_t initseq_d[] = {
0x11, // SLEEP_OUT (wake up)
0x3A, 2, // mode 8bpp (2= 8bpp, 3= 12bpp, 5= 16bpp)
0x36, 0b11000000, // my,mx,v,lao,rgb,x,x,x
0x25, 0x3a, // set contrast
0x29, // display on
0x03, // BSTRON (booster voltage)
0x2A, 1, RESX, 0x2B, 1, RESY
};
uint16_t initseq_c = ~(/* commands: 1, data: 0 */
(1 << 0) | (1 << 1) | (0 << 2) | (1 << 3) |
(0 << 4) | (1 << 5) | (0 << 6) | (1 << 7) |
(1 << 8) | (1 << 9) | (0 << 10) | (0 << 11) |
(1 << 12) | (0 << 13) | (0 << 14) | 0);
write(0, 0x01); /* most color displays need the pause */
delayms(10);
size_t i = 0;
while (i < sizeof(initseq_d)) {
write(initseq_c & 1, initseq_d[i++]);
initseq_c = initseq_c >> 1;
}
deselect();
rad1o_lcdFill(0xff); /* Clear display buffer */
rotate();
gpio_set(&gpio_lcd_bl_en);
}
void rad1o_lcdDeInit(void)
{
gpio_clear(&gpio_lcd_bl_en);
rad1o_lcdFill(0xff);
rad1o_lcdDisplay();
}
void rad1o_lcdFill(uint8_t f)
{
memset(lcdBuffer, f, RESX * RESY);
}
void rad1o_lcdSetPixel(uint8_t x, uint8_t y, uint8_t f)
{
if (x > RESX || y > RESY)
return;
lcdBuffer[y * RESX + x] = f;
}
static uint8_t getPixel(uint8_t x, uint8_t y)
{
return lcdBuffer[y * RESX + x];
}
uint8_t *rad1o_lcdGetBuffer(void)
{
return lcdBuffer;
}
void rad1o_lcdDisplay(void)
{
select();
uint16_t x, y;
/* set (back) to 8 bpp mode */
write(TYPE_CMD, 0x3a);
write(TYPE_DATA, 2);
write(TYPE_CMD, 0x2C); // memory write (RAMWR)
for (y = 0; y < RESY; y++) {
for (x = 0; x < RESX; x++) {
write(TYPE_DATA, getPixel(x, y));
};
}
deselect();
}
static void rotate(void)
{
select();
write(TYPE_CMD, 0x36); // MDAC-Command
if (isTurned) {
write(TYPE_DATA, 0b01100000); // my,mx,v,lao,rgb,x,x,x
isTurned = true;
} else {
write(TYPE_DATA, 0b11000000); // my,mx,v,lao,rgb,x,x,x
isTurned = false;
}
deselect();
rad1o_lcdDisplay();
}

View File

@ -0,0 +1,30 @@
#ifndef __RAD1O_DISPLAY_H__
#define __RAD1O_DISPLAY_H__
#include <libopencm3/cm3/common.h>
#include <stdint.h>
#define RESX 130
#define RESY 130
#define TYPE_CMD 0
#define TYPE_DATA 1
#define _PIN(pin, func, ...) pin
#define _FUNC(pin, func, ...) func
#define SETUPpin(args...) scu_pinmux(_PIN(args), _FUNC(args))
#define LCD_DI P1_4, SCU_CONF_FUNCTION5 | SCU_SSP_IO
#define LCD_SCK P1_19, SCU_CONF_FUNCTION1 | SCU_SSP_IO
#define LCD_SSP SSP1_NUM
void rad1o_lcdInit(void);
void rad1o_lcdDeInit(void);
void rad1o_lcdFill(uint8_t f);
void rad1o_lcdDisplay(void);
void rad1o_lcdSetPixel(uint8_t x, uint8_t y, uint8_t f);
uint8_t *rad1o_lcdGetBuffer(void);
#endif

View File

@ -0,0 +1,30 @@
#include "display.h"
#include <stdint.h>
#define SWAP(p1, p2) \
do { \
uint8_t SWAP = p1; \
p1 = p2; \
p2 = SWAP; \
} while (0)
void rad1o_drawHLine(uint8_t y, uint8_t x1, uint8_t x2, uint8_t color)
{
if (x1 > x2) {
SWAP(x1, x2);
}
for (uint8_t i = x1; i <= x2; ++i) {
rad1o_lcdSetPixel(i, y, color);
}
}
void rad1o_drawVLine(uint8_t x, uint8_t y1, uint8_t y2, uint8_t color)
{
if (y1 > y2) {
SWAP(y1, y2);
}
for (uint8_t i = y1; i <= y2; ++i) {
rad1o_lcdSetPixel(x, i, color);
}
}

View File

@ -0,0 +1,9 @@
#ifndef __RAD1O_DRAW_H__
#define __RAD1O_DRAW_H__
#include <stdint.h>
void rad1o_drawHLine(uint8_t y, uint8_t x1, uint8_t x2, uint8_t color);
void rad1o_drawVLine(uint8_t x, uint8_t y1, uint8_t y2, uint8_t color);
#endif

View File

@ -0,0 +1,35 @@
#ifndef __RAD1O_FONTS_H__
#define __RAD1O_FONTS_H__
#include <stdint.h>
/* Partially based on original code for the KS0108 by Stephane Rey */
/* Based on code code by Kevin Townsend */
typedef struct {
const uint8_t widthBits; // width, in bits (or pixels), of the character
} FONT_CHAR_INFO;
struct FONT_DEF {
uint8_t u8Width; /* Character width for storage */
uint8_t u8Height; /* Character height for storage */
uint8_t u8FirstChar; /* The first character available */
uint8_t u8LastChar; /* The last character available */
const uint8_t *au8FontTable; /* Font table start address in memory */
const FONT_CHAR_INFO *charInfo; /* Pointer to array of char information */
const uint16_t *charExtra; /* Pointer to array of extra char info */
};
struct EXTFONT {
uint8_t type; // 0: none, 1: static, 2: loaded
char name[13];
struct FONT_DEF def;
};
typedef const struct FONT_DEF *FONT;
#define FONT_DEFAULT 0
#define FONT_INTERNAL 1
#define FONT_EXTERNAL 2
#endif

View File

@ -0,0 +1,43 @@
#include "print.h"
#include "display.h"
#include "fonts.h"
#include "render.h"
#include "smallfonts.h"
static int32_t x = 0;
static int32_t y = 0;
void rad1o_lcdPrint(const char *string)
{
x = rad1o_DoString(x, y, string);
}
void rad1o_lcdNl(void)
{
x = 0;
y += rad1o_getFontHeight();
}
void rad1o_lcdClear(void)
{
x = 0;
y = 0;
rad1o_lcdFill(0xff);
}
void rad1o_lcdMoveCrsr(int32_t dx, int32_t dy)
{
x += dx;
y += dy;
}
void rad1o_lcdSetCrsr(int32_t dx, int32_t dy)
{
x = dx;
y = dy;
}
void rad1o_setSystemFont(void)
{
rad1o_setIntFont(&Font_7x8);
}

View File

@ -0,0 +1,13 @@
#ifndef __RAD1O_PRINT_H__
#define __RAD1O_PRINT_H__
#include <stdint.h>
void rad1o_lcdPrint(const char *string);
void rad1o_lcdNl(void);
void rad1o_lcdClear(void);
void rad1o_lcdMoveCrsr(int32_t dx, int32_t dy);
void rad1o_lcdSetCrsr(int32_t dx, int32_t dy);
void rad1o_setSystemFont(void);
#endif

View File

@ -0,0 +1,162 @@
#include "render.h"
#include "decoder.h"
#include "display.h"
#include "fonts.h"
#include "smallfonts.h"
#include <string.h>
/* Global Variables */
static const struct FONT_DEF *font = NULL;
static struct EXTFONT efont;
static uint8_t color_bg = 0xff; /* background color */
static uint8_t color_fg = 0x00; /* foreground color */
/* Exported Functions */
void rad1o_setTextColor(uint8_t bg, uint8_t fg)
{
color_bg = bg;
color_fg = fg;
}
void rad1o_setIntFont(const struct FONT_DEF *newfont)
{
memcpy(&efont.def, newfont, sizeof(struct FONT_DEF));
efont.type = FONT_INTERNAL;
font = &efont.def;
}
int rad1o_getFontHeight(void)
{
if (font)
return font->u8Height;
return 8; // XXX: Should be done right.
}
static int _getIndex(int c)
{
#define ERRCHR (font->u8FirstChar + 1)
/* Does this font provide this character? */
if (c < font->u8FirstChar)
c = ERRCHR;
if (c > font->u8LastChar && efont.type != FONT_EXTERNAL &&
font->charExtra == NULL)
c = ERRCHR;
if (c > font->u8LastChar &&
(efont.type == FONT_EXTERNAL || font->charExtra != NULL)) {
int cc = 0;
while (font->charExtra[cc] < c)
cc++;
if (font->charExtra[cc] > c)
c = ERRCHR;
else
c = font->u8LastChar + cc + 1;
};
c -= font->u8FirstChar;
return c;
}
int rad1o_DoChar(int sx, int sy, int c)
{
if (font == NULL) {
font = &Font_7x8;
};
/* how many bytes is it high? */
char height = (font->u8Height - 1) / 8 + 1;
char hoff = (8 - (font->u8Height % 8)) % 8;
const uint8_t *data;
int width, preblank = 0, postblank = 0;
do { /* Get Character data */
/* Get intex into character list */
c = _getIndex(c);
/* starting offset into character source data */
int toff = 0;
if (font->u8Width == 0) {
for (int y = 0; y < c; y++)
toff += font->charInfo[y].widthBits;
width = font->charInfo[c].widthBits;
toff *= height;
data = &font->au8FontTable[toff];
postblank = 1;
} else if (font->u8Width == 1) { // NEW CODE
// Find offset and length for our character
for (int y = 0; y < c; y++)
toff += font->charInfo[y].widthBits;
width = font->charInfo[c].widthBits;
if (font->au8FontTable[toff] >> 4 ==
15) { // It's a raw character!
preblank = font->au8FontTable[toff + 1];
postblank = font->au8FontTable[toff + 2];
data = &font->au8FontTable[toff + 3];
width = (width - 3 / height);
} else {
data = rad1o_pk_decode(
&font->au8FontTable[toff], &width);
}
} else {
toff = (c)*font->u8Width * 1;
width = font->u8Width;
data = &font->au8FontTable[toff];
};
} while (0);
#define xy_(x, y) \
((x < 0 || y < 0 || x >= RESX || y >= RESY) ? 0 : (y)*RESX + (x))
#define gPx(x, y) (data[x * height + (height - y / 8 - 1)] & (1 << (y % 8)))
int x = 0;
/* Fonts may not be byte-aligned, shift up so the top matches */
sy -= hoff;
sx += preblank;
uint8_t *lcdBuffer = rad1o_lcdGetBuffer();
/* per line */
for (int y = hoff; y < height * 8; y++) {
if (sy + y >= RESY)
continue;
/* Optional: empty space to the left */
for (int b = 1; b <= preblank; b++) {
if (sx >= RESX)
continue;
lcdBuffer[xy_(sx - b, sy + y)] = color_bg;
};
/* Render character */
for (x = 0; x < width; x++) {
if (sx + x >= RESX)
continue;
if (gPx(x, y)) {
lcdBuffer[xy_(sx + x, sy + y)] = color_fg;
} else {
lcdBuffer[xy_(sx + x, sy + y)] = color_bg;
};
};
/* Optional: empty space to the right */
for (int m = 0; m < postblank; m++) {
if (sx + x + m >= RESX)
continue;
lcdBuffer[xy_(sx + x + m, sy + y)] = color_bg;
};
};
return sx + (width + postblank);
}
int rad1o_DoString(int sx, int sy, const char *s)
{
const char *c;
for (c = s; *c != 0; c++) {
sx = rad1o_DoChar(sx, sy, *c);
};
return sx;
}

View File

@ -0,0 +1,11 @@
#ifndef __RENDER_H_
#define __RENDER_H_
#include "fonts.h"
void rad1o_setTextColor(uint8_t bg, uint8_t fg);
void rad1o_setIntFont(const struct FONT_DEF *font);
int rad1o_getFontHeight(void);
int rad1o_DoString(int sx, int sy, const char *s);
int rad1o_DoChar(int sx, int sy, int c);
#endif

View File

@ -0,0 +1,144 @@
/* Partially based on original code for the KS0108 by Stephane Rey */
/**************************************************************************/
/*!
@file smallfonts.c
@author K. Townsend (microBuilder.eu)
@date 22 March 2010
@version 0.10
@section LICENSE
Software License Agreement (BSD License)
Copyright (c) 2010, microBuilder SARL
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holders nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**************************************************************************/
#include "smallfonts.h"
/* System 7x8 */
const uint8_t au8Font7x8[] = {
0, 0, 0, 0, 0, 0, 0, //' '
0, 6, 95, 95, 6, 0, 0, //'!'
0, 7, 7, 0, 7, 7, 0, //'"'
20, 127, 127, 20, 127, 127, 20, //'#'
36, 46, 107, 107, 58, 18, 0, //'$'
70, 102, 48, 24, 12, 102, 98, //'%'
48, 122, 79, 93, 55, 122, 72, //'&'
4, 7, 3, 0, 0, 0, 0, //'''
0, 28, 62, 99, 65, 0, 0, //'('
0, 65, 99, 62, 28, 0, 0, //')'
8, 42, 62, 28, 28, 62, 42, //'*'
8, 8, 62, 62, 8, 8, 0, //'+'
0, 128, 224, 96, 0, 0, 0, //','
8, 8, 8, 8, 8, 8, 0, //'-'
0, 0, 96, 96, 0, 0, 0, //'.'
96, 48, 24, 12, 6, 3, 1, //'/'
62, 127, 113, 89, 77, 127, 62, //'0'
64, 66, 127, 127, 64, 64, 0, //'1'
98, 115, 89, 73, 111, 102, 0, //'2'
34, 99, 73, 73, 127, 54, 0, //'3'
24, 28, 22, 83, 127, 127, 80, //'4'
39, 103, 69, 69, 125, 57, 0, //'5'
60, 126, 75, 73, 121, 48, 0, //'6'
3, 3, 113, 121, 15, 7, 0, //'7'
54, 127, 73, 73, 127, 54, 0, //'8'
6, 79, 73, 105, 63, 30, 0, //'9'
0, 0, 102, 102, 0, 0, 0, //':'
0, 128, 230, 102, 0, 0, 0, //';'
8, 28, 54, 99, 65, 0, 0, //'<'
36, 36, 36, 36, 36, 36, 0, //'='
0, 65, 99, 54, 28, 8, 0, //'>'
2, 3, 81, 89, 15, 6, 0, //'?'
62, 127, 65, 93, 93, 31, 30, //'@'
124, 126, 19, 19, 126, 124, 0, //'A'
65, 127, 127, 73, 73, 127, 54, //'B'
28, 62, 99, 65, 65, 99, 34, //'C'
65, 127, 127, 65, 99, 62, 28, //'D'
65, 127, 127, 73, 93, 65, 99, //'E'
65, 127, 127, 73, 29, 1, 3, //'F'
28, 62, 99, 65, 81, 115, 114, //'G'
127, 127, 8, 8, 127, 127, 0, //'H'
0, 65, 127, 127, 65, 0, 0, //'I'
48, 112, 64, 65, 127, 63, 1, //'J'
65, 127, 127, 8, 28, 119, 99, //'K'
65, 127, 127, 65, 64, 96, 112, //'L'
127, 127, 14, 28, 14, 127, 127, //'M'
127, 127, 6, 12, 24, 127, 127, //'N'
28, 62, 99, 65, 99, 62, 28, //'O'
65, 127, 127, 73, 9, 15, 6, //'P'
30, 63, 33, 113, 127, 94, 0, //'Q'
65, 127, 127, 9, 25, 127, 102, //'R'
38, 111, 77, 89, 115, 50, 0, //'S'
3, 65, 127, 127, 65, 3, 0, //'T'
127, 127, 64, 64, 127, 127, 0, //'U'
31, 63, 96, 96, 63, 31, 0, //'V'
127, 127, 48, 24, 48, 127, 127, //'W'
67, 103, 60, 24, 60, 103, 67, //'X'
7, 79, 120, 120, 79, 7, 0, //'Y'
71, 99, 113, 89, 77, 103, 115, //'Z'
0, 127, 127, 65, 65, 0, 0, //'['
1, 3, 6, 12, 24, 48, 96, //'\'
0, 65, 65, 127, 127, 0, 0, //']'
8, 12, 6, 3, 6, 12, 8, //'^'
128, 128, 128, 128, 128, 128, 128, //'_'
0, 0, 3, 7, 4, 0, 0, //'`'
32, 116, 84, 84, 60, 120, 64, //'a'
65, 127, 63, 72, 72, 120, 48, //'b'
56, 124, 68, 68, 108, 40, 0, //'c'
48, 120, 72, 73, 63, 127, 64, //'d'
56, 124, 84, 84, 92, 24, 0, //'e'
72, 126, 127, 73, 3, 2, 0, //'f'
56, 188, 164, 164, 252, 120, 0, //'g'
65, 127, 127, 8, 4, 124, 120, //'h'
0, 68, 125, 125, 64, 0, 0, //'i'
96, 224, 128, 128, 253, 125, 0, //'j'
65, 127, 127, 16, 56, 108, 68, //'k'
0, 65, 127, 127, 64, 0, 0, //'l'
120, 124, 28, 56, 28, 124, 120, //'m'
124, 124, 4, 4, 124, 120, 0, //'n'
56, 124, 68, 68, 124, 56, 0, //'o'
0, 252, 252, 164, 36, 60, 24, //'p'
24, 60, 36, 164, 248, 252, 132, //'q'
68, 124, 120, 76, 4, 28, 24, //'r'
72, 92, 84, 84, 116, 36, 0, //'s'
0, 4, 62, 127, 68, 36, 0, //'t'
60, 124, 64, 64, 60, 124, 64, //'u'
28, 60, 96, 96, 60, 28, 0, //'v'
60, 124, 112, 56, 112, 124, 60, //'w'
68, 108, 56, 16, 56, 108, 68, //'x'
60, 188, 160, 160, 252, 124, 0, //'y'
76, 100, 116, 92, 76, 100, 0, //'z'
8, 8, 62, 119, 65, 65, 0, //'{'
0, 0, 0, 119, 119, 0, 0, //'|'
65, 65, 119, 62, 8, 8, 0, //'}'
2, 3, 1, 3, 2, 3, 1, //'~'
255, 129, 129, 129, 129, 129, 255, //'^?'
14, 159, 145, 177, 251, 74, 0 //'?'
};
/* Global variables */
const struct FONT_DEF Font_7x8 = { 7, 8, 32, 128, au8Font7x8, NULL, NULL };

View File

@ -0,0 +1,51 @@
/**************************************************************************/
/*!
@file smallfonts.h
@author K. Townsend (microBuilder.eu)
@date 22 March 2010
@version 0.10
@section LICENSE
Software License Agreement (BSD License)
Copyright (c) 2010, microBuilder SARL
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holders nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**************************************************************************/
#ifndef __RAD1O_SMALLFONTS_H__
#define __RAD1O_SMALLFONTS_H__
#include "fonts.h"
#include <stddef.h>
#include <stdint.h>
/* Partially based on original code for the KS0108 by Stephane Rey */
/* Current version by Kevin Townsend */
extern const struct FONT_DEF Font_7x8;
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
#ifndef __RAD1O_UBUNTU18_H__
#define __RAD1O_UBUNTU18_H__
#include "fonts.h"
extern const struct FONT_DEF Font_Ubuntu18pt;
#endif

View File

@ -554,6 +554,10 @@ static void portapack_ui_set_clock_source(clock_source_t source) {
portapack_lcd_draw_string(label_point, s); portapack_lcd_draw_string(label_point, s);
} }
static void portapack_ui_set_transceiver_mode(transceiver_mode_t mode) {
(void)mode;
}
static bool portapack_ui_operacake_gpio_compatible(void) { static bool portapack_ui_operacake_gpio_compatible(void) {
return false; return false;
} }
@ -573,6 +577,7 @@ const hackrf_ui_t portapack_hackrf_ui = {
&portapack_ui_set_filter, &portapack_ui_set_filter,
&portapack_ui_set_antenna_bias, &portapack_ui_set_antenna_bias,
&portapack_ui_set_clock_source, &portapack_ui_set_clock_source,
&portapack_ui_set_transceiver_mode,
&portapack_ui_operacake_gpio_compatible, &portapack_ui_operacake_gpio_compatible,
}; };

View File

@ -21,78 +21,287 @@
#include "ui_rad1o.h" #include "ui_rad1o.h"
/* Weak functions from rad1o app */ #include "rad1o/display.h"
void hackrf_ui_init(void) __attribute__((weak)); #include "rad1o/draw.h"
void hackrf_ui_setFrequency(uint64_t _freq) __attribute__((weak)); #include "rad1o/print.h"
void hackrf_ui_setSampleRate(uint32_t _sample_rate) __attribute__((weak)); #include "rad1o/render.h"
void hackrf_ui_setDirection(const rf_path_direction_t _direction) __attribute__((weak)); #include "rad1o/smallfonts.h"
void hackrf_ui_setFilterBW(uint32_t bw) __attribute__((weak)); #include "rad1o/ubuntu18.h"
void hackrf_ui_setLNAPower(bool _lna_on) __attribute__((weak));
void hackrf_ui_setBBLNAGain(const uint32_t gain_db) __attribute__((weak));
void hackrf_ui_setBBVGAGain(const uint32_t gain_db) __attribute__((weak));
void hackrf_ui_setBBTXVGAGain(const uint32_t gain_db) __attribute__((weak));
void hackrf_ui_setFirstIFFrequency(const uint64_t freq) __attribute__((weak));
void hackrf_ui_setFilter(const rf_path_filter_t filter) __attribute__((weak));
void hackrf_ui_setAntennaBias(bool antenna_bias) __attribute__((weak));
void hackrf_ui_setClockSource(clock_source_t source) __attribute__((weak));
static void rad1o_ui_init(void) { #include <stdio.h>
hackrf_ui_init();
static uint64_t freq = 0;
static uint32_t sample_rate = 0;
static uint32_t filter_bw = 0;
static rf_path_direction_t direction;
static uint32_t bblna_gain = 0;
static uint32_t bbvga_gain = 0;
static uint32_t bbtxvga_gain = 0;
static bool lna_on = false;
static transceiver_mode_t trx_mode;
static bool enabled = false;
#define BLACK 0b00000000
#define RED 0b11100000
#define RED_DARK 0b01100000
#define GREEN 0b00011100
#define GREEN_DARK 0b00001100
#define BLUE 0b00000011
#define WHITE 0b11111111
#define GREY 0b01001101
static void draw_frequency(void)
{
char tmp[100];
uint32_t mhz;
uint32_t khz;
mhz = freq / 1000000;
khz = (freq - mhz * 1000000) / 1000;
rad1o_setTextColor(BLACK, GREEN);
rad1o_setIntFont(&Font_Ubuntu18pt);
sprintf(tmp, "%4u.%03u", (unsigned int)mhz, (unsigned int)khz);
rad1o_lcdPrint(tmp);
rad1o_setIntFont(&Font_7x8);
rad1o_lcdMoveCrsr(1, 18 - 7);
rad1o_lcdPrint("MHz");
} }
static void rad1o_ui_deinit(void) { static void draw_tx_rx(void)
{
uint8_t bg, fg;
rad1o_setIntFont(&Font_Ubuntu18pt);
bg = BLACK;
fg = GREY;
if (direction == RF_PATH_DIRECTION_OFF) {
fg = WHITE;
}
rad1o_setTextColor(bg, fg);
rad1o_lcdPrint("OFF ");
fg = GREY;
if (direction == RF_PATH_DIRECTION_RX) {
fg = GREEN;
}
rad1o_setTextColor(bg, fg);
rad1o_lcdPrint("RX ");
fg = GREY;
if (direction == RF_PATH_DIRECTION_TX) {
fg = RED;
}
rad1o_setTextColor(bg, fg);
rad1o_lcdPrint("TX");
rad1o_setIntFont(&Font_7x8);
} }
static void rad1o_ui_set_frequency(uint64_t frequency) { static void ui_update(void)
hackrf_ui_setFrequency(frequency); {
char tmp[100];
uint32_t mhz;
uint32_t khz;
if (!enabled) {
return;
}
rad1o_lcdClear();
rad1o_lcdFill(0x00);
rad1o_drawHLine(0, 0, RESX - 1, WHITE);
rad1o_drawVLine(0, 0, RESY - 1, WHITE);
rad1o_drawHLine(RESY - 1, 0, RESX - 1, WHITE);
rad1o_drawVLine(RESX - 1, 0, RESY - 1, WHITE);
rad1o_lcdSetCrsr(25, 2);
rad1o_setTextColor(BLACK, GREEN);
rad1o_lcdPrint("HackRF Mode");
rad1o_lcdNl();
rad1o_drawHLine(11, 0, RESX - 1, WHITE);
rad1o_lcdSetCrsr(2, 12);
if (trx_mode == TRANSCEIVER_MODE_RX_SWEEP) {
rad1o_setIntFont(&Font_Ubuntu18pt);
rad1o_lcdPrint("SWEEP");
} else {
draw_frequency();
}
rad1o_drawHLine(40, 0, RESX - 1, WHITE);
rad1o_lcdSetCrsr(6, 41);
draw_tx_rx();
rad1o_drawHLine(69, 0, RESX - 1, WHITE);
rad1o_setTextColor(BLACK, WHITE);
rad1o_lcdSetCrsr(2, 71);
rad1o_lcdPrint("Rate: ");
mhz = sample_rate / 1000000;
khz = (sample_rate - mhz * 1000000) / 1000;
sprintf(tmp, "%2u.%03u MHz", (unsigned int)mhz, (unsigned int)khz);
rad1o_lcdPrint(tmp);
rad1o_lcdNl();
rad1o_lcdMoveCrsr(2, 0);
rad1o_lcdPrint("Filter: ");
mhz = filter_bw / 1000000;
khz = (filter_bw - mhz * 1000000) / 1000;
sprintf(tmp, "%2u.%03u MHz", (unsigned int)mhz, (unsigned int)khz);
rad1o_lcdPrint(tmp);
rad1o_lcdNl();
rad1o_drawHLine(88, 0, RESX - 1, WHITE);
rad1o_setTextColor(BLACK, WHITE);
rad1o_lcdSetCrsr(2, 90);
rad1o_lcdPrint(" Gains");
rad1o_lcdNl();
rad1o_setTextColor(BLACK, GREEN);
rad1o_lcdMoveCrsr(2, 2);
rad1o_lcdPrint("AMP: ");
if (lna_on) {
rad1o_setTextColor(BLACK, RED);
rad1o_lcdPrint("ON ");
} else {
rad1o_lcdPrint("OFF");
}
rad1o_setTextColor(BLACK, RED_DARK);
if (direction == RF_PATH_DIRECTION_TX) {
rad1o_setTextColor(BLACK, RED);
}
sprintf(tmp, " TX: %u dB", (unsigned int)bbtxvga_gain);
rad1o_lcdPrint(tmp);
rad1o_lcdNl();
rad1o_lcdMoveCrsr(2, 0);
rad1o_setTextColor(BLACK, GREEN_DARK);
if (direction == RF_PATH_DIRECTION_RX) {
rad1o_setTextColor(BLACK, GREEN);
}
sprintf(tmp, "LNA: %2u dB", (unsigned int)bblna_gain);
rad1o_lcdPrint(tmp);
rad1o_lcdNl();
rad1o_lcdMoveCrsr(2, 0);
sprintf(tmp, "VGA: %2u dB", (unsigned int)bbvga_gain);
rad1o_lcdPrint(tmp);
rad1o_lcdNl();
rad1o_lcdDisplay();
// Don't ask...
ssp1_set_mode_max2837();
} }
static void rad1o_ui_set_sample_rate(uint32_t sample_rate) { static void rad1o_ui_init(void)
hackrf_ui_setSampleRate(sample_rate); {
rad1o_lcdInit();
enabled = true;
ui_update();
} }
static void rad1o_ui_set_direction(const rf_path_direction_t direction) { static void rad1o_ui_deinit(void)
hackrf_ui_setDirection(direction); {
rad1o_lcdDeInit();
enabled = false;
// Don't ask...
ssp1_set_mode_max2837();
} }
static void rad1o_ui_set_filter_bw(uint32_t bandwidth) { static void rad1o_ui_set_frequency(uint64_t frequency)
hackrf_ui_setFilterBW(bandwidth); {
freq = frequency;
if (TRANSCEIVER_MODE_RX_SWEEP == trx_mode) {
} else {
ui_update();
}
} }
static void rad1o_ui_set_lna_power(bool lna_on) { static void rad1o_ui_set_sample_rate(uint32_t _sample_rate)
hackrf_ui_setLNAPower(lna_on); {
sample_rate = _sample_rate;
ui_update();
} }
static void rad1o_ui_set_bb_lna_gain(const uint32_t gain_db) { static void rad1o_ui_set_direction(const rf_path_direction_t _direction)
hackrf_ui_setBBLNAGain(gain_db); {
direction = _direction;
ui_update();
} }
static void rad1o_ui_set_bb_vga_gain(const uint32_t gain_db) { static void rad1o_ui_set_filter_bw(uint32_t bandwidth)
hackrf_ui_setBBVGAGain(gain_db); {
filter_bw = bandwidth;
ui_update();
} }
static void rad1o_ui_set_bb_tx_vga_gain(const uint32_t gain_db) { static void rad1o_ui_set_lna_power(bool _lna_on)
hackrf_ui_setBBTXVGAGain(gain_db); {
lna_on = _lna_on;
ui_update();
} }
static void rad1o_ui_set_first_if_frequency(const uint64_t frequency) { static void rad1o_ui_set_bb_lna_gain(const uint32_t gain_db)
hackrf_ui_setFirstIFFrequency(frequency); {
bblna_gain = gain_db;
ui_update();
} }
static void rad1o_ui_set_filter(const rf_path_filter_t filter) { static void rad1o_ui_set_bb_vga_gain(const uint32_t gain_db)
hackrf_ui_setFilter(filter); {
bbvga_gain = gain_db;
ui_update();
} }
static void rad1o_ui_set_antenna_bias(bool antenna_bias) { static void rad1o_ui_set_bb_tx_vga_gain(const uint32_t gain_db)
hackrf_ui_setAntennaBias(antenna_bias); {
bbtxvga_gain = gain_db;
ui_update();
} }
static void rad1o_ui_set_clock_source(clock_source_t source) { static void rad1o_ui_set_first_if_frequency(const uint64_t frequency
hackrf_ui_setClockSource(source); __attribute__((unused)))
{
// Not implemented
} }
static bool rad1o_ui_operacake_gpio_compatible(void) { static void rad1o_ui_set_filter(const rf_path_filter_t filter
__attribute__((unused)))
{
// Not implemented
}
static void rad1o_ui_set_antenna_bias(bool antenna_bias __attribute__((unused)))
{
// Not implemented
}
static void rad1o_ui_set_clock_source(clock_source_t source
__attribute__((unused)))
{
// Not implemented
}
static void rad1o_ui_set_transceiver_mode(transceiver_mode_t mode)
{
trx_mode = mode;
ui_update();
}
static bool rad1o_ui_operacake_gpio_compatible(void)
{
return true; return true;
} }
@ -111,9 +320,11 @@ static const hackrf_ui_t rad1o_ui = {
&rad1o_ui_set_filter, &rad1o_ui_set_filter,
&rad1o_ui_set_antenna_bias, &rad1o_ui_set_antenna_bias,
&rad1o_ui_set_clock_source, &rad1o_ui_set_clock_source,
&rad1o_ui_set_transceiver_mode,
&rad1o_ui_operacake_gpio_compatible, &rad1o_ui_operacake_gpio_compatible,
}; };
const hackrf_ui_t* rad1o_ui_setup(void) { const hackrf_ui_t *rad1o_ui_setup(void)
{
return &rad1o_ui; return &rad1o_ui;
} }

View File

@ -24,6 +24,6 @@
#include "hackrf_ui.h" #include "hackrf_ui.h"
const hackrf_ui_t* rad1o_ui_setup(void) __attribute__((weak)); const hackrf_ui_t *rad1o_ui_setup(void) __attribute__((weak));
#endif/*__UI_RAD1O_H__*/ #endif /*__UI_RAD1O_H__*/

View File

@ -76,6 +76,13 @@ endif()
if(BOARD STREQUAL "RAD1O") if(BOARD STREQUAL "RAD1O")
SET(SRC_M4 SET(SRC_M4
${SRC_M4} ${SRC_M4}
"${PATH_HACKRF_FIRMWARE_COMMON}/rad1o/display.c"
"${PATH_HACKRF_FIRMWARE_COMMON}/rad1o/print.c"
"${PATH_HACKRF_FIRMWARE_COMMON}/rad1o/render.c"
"${PATH_HACKRF_FIRMWARE_COMMON}/rad1o/decoder.c"
"${PATH_HACKRF_FIRMWARE_COMMON}/rad1o/smallfonts.c"
"${PATH_HACKRF_FIRMWARE_COMMON}/rad1o/draw.c"
"${PATH_HACKRF_FIRMWARE_COMMON}/rad1o/ubuntu18.c"
"${PATH_HACKRF_FIRMWARE_COMMON}/ui_rad1o.c" "${PATH_HACKRF_FIRMWARE_COMMON}/ui_rad1o.c"
) )
endif() endif()

View File

@ -262,6 +262,8 @@ void set_transceiver_mode(const transceiver_mode_t new_transceiver_mode) {
_transceiver_mode = new_transceiver_mode; _transceiver_mode = new_transceiver_mode;
hackrf_ui()->set_transceiver_mode(_transceiver_mode);
switch (_transceiver_mode) { switch (_transceiver_mode) {
case TRANSCEIVER_MODE_RX_SWEEP: case TRANSCEIVER_MODE_RX_SWEEP:
case TRANSCEIVER_MODE_RX: case TRANSCEIVER_MODE_RX: