diff options
-rw-r--r-- | draw/glui.h | 40 | ||||
-rw-r--r-- | draw/make.mk | 2 | ||||
-rw-r--r-- | draw/tui.c | 214 | ||||
-rw-r--r-- | draw/tui.h | 15 | ||||
-rw-r--r-- | test/.gitignore | 1 | ||||
-rw-r--r-- | test/Makefile | 2 | ||||
-rwxr-xr-x | test/colors.sh | 25 | ||||
-rw-r--r-- | test/ui_gl_waterfall.c | 7 | ||||
-rw-r--r-- | test/ui_tui_waterfall.c | 325 |
9 files changed, 618 insertions, 13 deletions
diff --git a/draw/glui.h b/draw/glui.h index e69de29..d55f931 100644 --- a/draw/glui.h +++ b/draw/glui.h @@ -0,0 +1,40 @@ +#ifndef __RADIOLA_GLUI_H +#define __RADIOLA_GLUI_H + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +//to draw waterfall +typedef struct glui_waterfall_t +{ + int type; + int h,w; + uint8_t *buf; + size_t buf_len; +} glui_waterfall_t; + +typedef struct glui_t +{ + glui_waterfall_t *wf; +} glui_t; + +//prepare terminal ui +int glui_init( glui_t **t ); +//init waterfall +int glui_waterfall( glui_t **t, glui_waterfall_t **w ); +//first draw, draw all buffer +int glui_waterfall_draw( glui_waterfall_t *w ); +//redraw only changed lines +int glui_waterfall_redraw( glui_waterfall_t *w ); +//update params of waterfall and then need to draw not redraw +int glui_waterfall_update( glui_t *w ); +//push one line of data to buffer +int glui_waterfall_data( glui_t *w, int len, uint8_t *buf ); +//return color +uint8_t glui_waterfall_color( uint8_t d ); +//close terminal ui +int glui_close( glui_t *t );
\ No newline at end of file diff --git a/draw/make.mk b/draw/make.mk index 1ce35d1..9756446 100644 --- a/draw/make.mk +++ b/draw/make.mk @@ -1,7 +1,7 @@ DIR_DRAW = draw/ SOURCES_DRAW += draw/glui.c draw/tui.c draw/ui.c OBJECTS_DRAW += $(SOURCES_DRAW:.c=.o) -LDFLAGS += +LDFLAGS += -lGL OBJECTS_DIR_DRAW += $(subst $(DIR_DRAW),$(BUILD_DIR)$(DIR_DRAW),$(OBJECTS_DRAW)) @@ -1,24 +1,95 @@ #include "tui.h" +#define T_ESC "\x1b" + //prepare terminal ui -int tui_init( tui_t *t ) +int tui_init( tui_t **t ) { int ret = -1; + tui_t *tui=NULL; + //should be empty pointer - if (t != NULL) + if (*t != NULL) + return -1; + + tui = malloc( sizeof(tui_t) ); + if ( tui == NULL ) return -1; + + memset( tui, 0, sizeof( tui_t ) ); + + tui->ifd = STDIN_FILENO; + tui->ofd = STDOUT_FILENO; + + //if you whant raw mode then you should set it man + if ( tcgetattr( tui->ifd, &tui->orig_i ) == -1 ) + goto exit_error; + tui->raw_i = tui->orig_i; + + if ( tcgetattr( tui->ofd, &tui->orig_o ) == -1 ) + goto exit_error; + tui->raw_o = tui->orig_o; + + //set not to echo output + /* input modes: no break, no CR to NL, no parity check, no strip char, + * no start/stop output control. */ + tui->raw_i.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + /* output modes - disable post raw */ + tui->raw_i.c_oflag &= ~(OPOST); + /* control modes - set 8 bit chars */ + tui->raw_i.c_cflag |= (CS8); + /* local modes - choing off, canonical off, no extended functions, + * no signal chars (^Z,^C) */ + tui->raw_i.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); + /* control chars - set return condition: min number of bytes and timer. + * We want read to return every single byte, without timeout. */ + + /* put terminal in raw mode after flushing */ + if (tcsetattr( tui->ifd, TCSAFLUSH, &tui->raw_i) < 0) + { + //ERROR("Cannot set new terminal input attribures\n"); + goto exit_error; + } + + *t = tui; + ret = 0; + return ret; + +exit_error: + free( tui ); + return -1; } //init waterfall -int tui_waterfall( tui_t *t, tui_waterfall_t *w ) +int tui_waterfall( tui_t **t, tui_waterfall_t **w ) { int ret=-1; + tui_waterfall_t *wtf = NULL; + //waterfall should be NULL - if ( w != NULL ) + if ( *w != NULL ) + return -1; + + + wtf = malloc( sizeof(tui_waterfall_t) ); + if ( wtf == NULL ) + { return -1; + } + + memset( wtf, 0, sizeof(tui_waterfall_t) ); + + *w = wtf; + (*t)->wf = wtf; + ret = 0; + return ret; + +//exit_error: + +// return -1; } @@ -39,27 +110,158 @@ int tui_waterfall_redraw( tui_waterfall_t *w ) //update params of waterfall and then need to draw not redraw -int tui_waterfall_update( tui_waterfall_t *w ) +int tui_waterfall_update( tui_t *t ) { int ret = -1; + int row=-1,col=-1; + char buf[32]; + int i; + + //we trust that all params are ok + + /* go to right marging and get position */ + if ( write( t->ofd, "\x1b[999C", 6 ) != 6 ) + goto exit_error; + + if ( write( t->ofd, "\x1b[6n", 4 ) != 4 ) + goto exit_error; + + i = 0; + //printf("here=%d\n", sizeof(buf)); + while (i < sizeof(buf)-1) + { + if ( read( t->ifd, buf+i,1 ) != 1 ) break; + if (buf[i] == 'R') break; + i++; + } + buf[i] = '\0'; + //printf("i=%d,buf=[%s]\n",i,buf); + + if ( buf[0] != '\x1b' || buf[1] != '[' ) + { + goto exit_error; + } + + //printf("i=%d,buf=[%s]\n",i,buf); + + if ( sscanf( buf+2, "%d;%d", &row, &col) != 2 ) + goto exit_error; + + //write( t->ofd, "\x1b[1C", 4 ); + write( t->ofd, T_ESC "[H" T_ESC "[2J", 7 ); + write( t->ofd, T_ESC "[0;0H", 6); + + t->wf->w = col; + + ret = 0; + return ret; + +exit_error: + + return -1; } //push one line of data to buffer -int tui_waterfall_data( tui_waterfall_t *w, size_t *len, size_t *buf ) +int tui_waterfall_data( tui_t *t, int len, uint8_t *buf ) { int ret = -1; + int i; + + + + i = 0; + while ( (i< t->wf->w) && ( i<len) ) + { + //printf("-%d", buf[i]); + uint8_t c = tui_waterfall_color( buf[i] ); + char buf[32]; + snprintf( buf, 32, T_ESC "[48;5;%dm " T_ESC "[0m",c); + write( t->ofd, buf, strlen(buf) ); + i++; + } + return ret; } +uint8_t tui_waterfall_color( uint8_t d ) +{ + + uint8_t color=15; + + /* + if ( d < 50 ) + { + color = 17; + } else if ( d < 100 ) + { + color = 18; + } else if ( d < 150 ) + { + color = 19; + } else if ( d < 200 ) + { + color = 20; + } else + { + color = 21; + } + */ + + + if ( d == 0 ) + { + color = 17; + } else if ( d == 1 ) + { + color = 18; + } else if ( d == 2 ) + { + color = 19; + } else if ( d == 3 ) + { + color = 20; + } else if ( d == 4 ) + { + color = 21; + } else if ( d == 5 ) + { + color = 26; + } else if ( d == 6 ) + { + color = 27; + } else if ( d == 7 ) + { + color = 44; + } else + { + color = 230; + } + + /* + uint8_t col[] = { 16,17,18,19,20,21,26,27,44,45,86,87,230,229,228,227,226,214,202,196,160,124,88,52 }; + int len = 24; + int step = 256/len; + + color = col[d/step]; + */ + + return color; +} + //close terminal ui int tui_close( tui_t *t ) { int ret = -1; + //shouldnt be empty pointer if ( t == NULL ) return -1; + + //restore terminal mode after closing + tcsetattr( t->ifd, TCSAFLUSH, &t->orig_i ); + return ret; } @@ -2,7 +2,9 @@ #define __RADIOLA_TUI_H #include <stdio.h> +#include <stdint.h> #include <stdlib.h> +#include <string.h> #include <termios.h> #include <unistd.h> @@ -11,7 +13,8 @@ typedef struct tui_waterfall_t { int type; int h,w; - + uint8_t *buf; + size_t buf_len; } tui_waterfall_t; typedef struct tui_t @@ -23,17 +26,19 @@ typedef struct tui_t } tui_t; //prepare terminal ui -int tui_init( tui_t *t ); +int tui_init( tui_t **t ); //init waterfall -int tui_waterfall( tui_t *t, tui_waterfall_t *w ); +int tui_waterfall( tui_t **t, tui_waterfall_t **w ); //first draw, draw all buffer int tui_waterfall_draw( tui_waterfall_t *w ); //redraw only changed lines int tui_waterfall_redraw( tui_waterfall_t *w ); //update params of waterfall and then need to draw not redraw -int tui_waterfall_update( tui_waterfall_t *w ); +int tui_waterfall_update( tui_t *w ); //push one line of data to buffer -int tui_waterfall_data( tui_waterfall_t *w, size_t *len, size_t *buf ); +int tui_waterfall_data( tui_t *w, int len, uint8_t *buf ); +//return color +uint8_t tui_waterfall_color( uint8_t d ); //close terminal ui int tui_close( tui_t *t ); diff --git a/test/.gitignore b/test/.gitignore index bc5e3c4..c096546 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -1,4 +1,5 @@ get_device_list read_samples ui_tui_waterfall +ui_gl_waterfall *.o diff --git a/test/Makefile b/test/Makefile index 7fb106d..348fd86 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,7 +1,7 @@ CC=gcc CFLAGS=-I../ #LDFLAGS= `pkg-config --libs libusb` -L../../../r820t -lr820t -Wl,-rpath=../../../r820t -LDFLAGS=`pkg-config --libs libusb` -lrtlsdr ../radiola.o +LDFLAGS=`pkg-config --libs libusb` -lrtlsdr -lm ../radiola.o SOURCE = $(wildcard *.c) OBJECTS = BIN = $(SOURCE:.c=) diff --git a/test/colors.sh b/test/colors.sh new file mode 100755 index 0000000..7882c40 --- /dev/null +++ b/test/colors.sh @@ -0,0 +1,25 @@ +echo -en "\e[38;5;16m#\e[0m" +echo -en "\e[38;5;17m#\e[0m" +echo -en "\e[38;5;18m#\e[0m" +echo -en "\e[38;5;19m#\e[0m" +echo -en "\e[38;5;20m#\e[0m" +echo -en "\e[38;5;21m#\e[0m" +echo -en "\e[38;5;26m#\e[0m" +echo -en "\e[38;5;27m#\e[0m" +echo -en "\e[38;5;44m#\e[0m" +echo -en "\e[38;5;45m#\e[0m" +echo -en "\e[38;5;86m#\e[0m" +echo -en "\e[38;5;87m#\e[0m" +echo -en "\e[38;5;230m#\e[0m" +echo -en "\e[38;5;229m#\e[0m" +echo -en "\e[38;5;228m#\e[0m" +echo -en "\e[38;5;227m#\e[0m" +echo -en "\e[38;5;226m#\e[0m" +echo -en "\e[38;5;214m#\e[0m" +echo -en "\e[38;5;202m#\e[0m" +echo -en "\e[38;5;202m#\e[0m" +echo -en "\e[38;5;196m#\e[0m" +echo -en "\e[38;5;160m#\e[0m" +echo -en "\e[38;5;124m#\e[0m" +echo -en "\e[38;5;88m#\e[0m" +echo -en "\e[38;5;52m#\e[0m"
\ No newline at end of file diff --git a/test/ui_gl_waterfall.c b/test/ui_gl_waterfall.c new file mode 100644 index 0000000..40872c8 --- /dev/null +++ b/test/ui_gl_waterfall.c @@ -0,0 +1,7 @@ +#include <stdio.h> +#include <stdlib.h> + +int main() +{ + return 0; +}
\ No newline at end of file diff --git a/test/ui_tui_waterfall.c b/test/ui_tui_waterfall.c index a0a83bc..43a21e9 100644 --- a/test/ui_tui_waterfall.c +++ b/test/ui_tui_waterfall.c @@ -1,11 +1,336 @@ +#include <math.h> #include <stdio.h> #include <stdlib.h> +#include <unistd.h> //radiola #include <draw/tui.h> +#include <hw/hw.h> + +#define SAMPLE_RATE 2048000 + +#define CENTER_FREQ 100500000 +#define FFT_LEVEL 10 +#define FFT_SIZE (1 << FFT_LEVEL) +#define BUF_LENGHT (2 * FFT_SIZE) +#define PRESCALE 8 +#define POSTSCALE 2 + +static rtlsdr_dev_t *dev = NULL; + +int16_t* Sinewave; +int N_WAVE, LOG2_N_WAVE; +double* power_table; + +int sdr_init() +{ + int ret; + uint32_t dev_index = 0; + + //open tunner + ret = rtlsdr_open(&dev, (uint32_t)dev_index); + if ( ret < 0 ) + { + printf("Cannot open device %02d\n", dev_index ); + return -1; + } + + ret = rtlsdr_reset_buffer(dev); + if ( ret < 0 ) + { + printf("Couldnt reset buffer\n"); + return -1; + } + + ret = rtlsdr_set_sample_rate(dev, SAMPLE_RATE); + if ( ret < 0 ) + { + printf("Coulnt set sample rate to %d\n", SAMPLE_RATE); + return -1; + } + + ret = rtlsdr_set_center_freq( dev, CENTER_FREQ ); + if ( ret < 0 ) + { + printf("Couldnt set freq %d\n", CENTER_FREQ); + return -1; + } + + ret = rtlsdr_set_tuner_gain_mode( dev, 1 ); + if ( ret < 0 ) + { + printf("Cannot set auto gain mode\n"); + return -1; + } + + ret = rtlsdr_set_agc_mode( dev, 1); + if ( ret < 0 ) + { + printf("Cannot set agc mode\n"); + return -1; + } + + return 0; +} + + +int sdr_close() +{ + //close tunner + if ( dev != NULL) + { + rtlsdr_close( dev ); + dev = NULL; + return 0; + } + return -1; +} + +int sdr_get_samples( uint8_t *buf, int len ) +{ + int ret, read_num; + + ret = rtlsdr_read_sync( dev, buf, len, &read_num ); + if (ret < 0) + { + printf("sync read failed\n"); + return -1; + } + + return 0; +} + +//better to have size size mod olen == 0 +int normalise( uint8_t *ibuf, int ilen, uint8_t *obuf, int olen ) +{ + int i,j,m; + int ppi; + + if ( ilen >= olen ) + { + ppi = ilen / olen; + } else { + return -1; + } + m = 0; + i = 0; + while ( (i < ilen) && (m < olen) ) + { + uint32_t sum=0; + for ( j=0; j<ppi; j++ ); + sum += ibuf[i+j]; + sum /= ppi; + obuf[m] = sum; + //printf("%d-", obuf[m] ); + + i += ppi; + m += 1; + } + + return 0; +} + +void sine_table(int size) +{ + int i; + double d; + LOG2_N_WAVE = size; + N_WAVE = 1 << LOG2_N_WAVE; + Sinewave = malloc(sizeof(int16_t) * N_WAVE*3/4); + power_table = malloc(sizeof(double) * N_WAVE); + for (i=0; i<N_WAVE*3/4; i++) + { + d = (double)i * 2.0 * M_PI / N_WAVE; + Sinewave[i] = (int)round(32767*sin(d)); + } +} + +int16_t FIX_MPY(int16_t a, int16_t b) +/* fixed point multiply and scale */ +{ + int c = ((int)a * (int)b) >> 14; + b = c & 0x01; + return (c >> 1) + b; +} + +int32_t real_conj(int16_t real, int16_t imag) +/* real(n * conj(n)) */ +{ + return ((int32_t)real*(int32_t)real + (int32_t)imag*(int32_t)imag); +} + +int fix_fft(int16_t iq[], int m) +/* interleaved iq[], 0 <= n < 2**m, changes in place */ +{ + int mr, nn, i, j, l, k, istep, n, shift; + int16_t qr, qi, tr, ti, wr, wi; + n = 1 << m; + if (n > N_WAVE) + {return -1;} + mr = 0; + nn = n - 1; + /* decimation in time - re-order data */ + for (m=1; m<=nn; ++m) { + l = n; + do + {l >>= 1;} + while (mr+l > nn); + mr = (mr & (l-1)) + l; + if (mr <= m) + {continue;} + // real = 2*m, imag = 2*m+1 + tr = iq[2*m]; + iq[2*m] = iq[2*mr]; + iq[2*mr] = tr; + ti = iq[2*m+1]; + iq[2*m+1] = iq[2*mr+1]; + iq[2*mr+1] = ti; + } + l = 1; + k = LOG2_N_WAVE-1; + while (l < n) { + shift = 1; + istep = l << 1; + for (m=0; m<l; ++m) { + j = m << k; + wr = Sinewave[j+N_WAVE/4]; + wi = -Sinewave[j]; + if (shift) { + wr >>= 1; wi >>= 1;} + for (i=m; i<n; i+=istep) { + j = i + l; + tr = FIX_MPY(wr,iq[2*j]) - FIX_MPY(wi,iq[2*j+1]); + ti = FIX_MPY(wr,iq[2*j+1]) + FIX_MPY(wi,iq[2*j]); + qr = iq[2*i]; + qi = iq[2*i+1]; + if (shift) { + qr >>= 1; qi >>= 1;} + iq[2*j] = qr - tr; + iq[2*j+1] = qi - ti; + iq[2*i] = qr + tr; + iq[2*i+1] = qi + ti; + } + } + --k; + l = istep; + } + return 0; +} + +//fftize +int simple_fft( uint8_t *buf, int len ) +{ + int i,j; + uint16_t p; + int fft_len; + + for (i=0; i<len; i++) + { + buf[i] = buf[i] * PRESCALE; + } + + fix_fft( (uint16_t *)buf, FFT_LEVEL ); + + for (i=0; i<FFT_SIZE; i++) + { + //buf1[i] = rtl_out.buf[i]; + //p = buf1[i] * buf1[i]; + j = i*2; + p = (int16_t)real_conj(buf[j], buf[j + 1]); + buf[i] += p; + } + + fft_len = FFT_SIZE / 2; + for (i=0; i<fft_len; i++) + { + buf[i] = (int)log10(POSTSCALE * (float)buf[i+fft_len]); + buf[i+fft_len] = (int)log10(POSTSCALE * (float)buf[i]); + } + + return 0; +} int main() { + int i,j; + uint8_t *buf, *sample_buf; + int buf_len, sample_len; + uint32_t dev_num; + + tui_t *t = NULL; + tui_waterfall_t *w = NULL; + + if ( sdr_init() == -1 ) + { + goto main_exit; + } + + sine_table( FFT_LEVEL ); + + + //printf("%x\n",t); + //open GUI + if ( tui_init( &t ) == -1 ) + { + printf("Cannot set tui\n"); + return 1; + } + + //printf("%x\n",t); + if ( tui_waterfall( &t, &w ) == -1 ) + { + printf("Cannot set waterfall\n"); + return 1; + } + + if ( tui_waterfall_update( t ) == -1) + { + printf("Cannot update waterfall size\n"); + return -1; + } + + dev_num = rtlsdr_get_device_count(); + if ( dev_num < 1 ) + { + printf( "Cannot find any device" ); + goto main_exit; + } + + + + buf_len = sizeof(char)*w->w; + buf = malloc( buf_len ); + + sample_len = BUF_LENGHT; + sample_buf = malloc( sample_len ); + + srand(0); //fake seed + for ( i=0; i<20;i++ ) + { + //for (j=0; j<buf_len; j++) + // sample_buf[j] = (uint8_t)((rand()&0xff)); + + //read some samples + sdr_get_samples( sample_buf, sample_len ); + + //do fft + //simple_fft( sample_buf, sample_len/2 ); + + //prepare to show on the screen + if (normalise( sample_buf, sample_len, buf, buf_len ) == -1) + { + printf("Cannot normalise\n"); + } + tui_waterfall_data( t, buf_len, buf ); + //printf("\n\b"); + sleep(1); + } + +main_exit: + //close gui, restore terminal mode + tui_close( t ); + sdr_close(); + return 0; }
\ No newline at end of file |