Существует простенький код на c/c++ сканера частот nrf, представленный в этой статье. Однажды я подумал, что не плохо было бы как-то визуализировать бездушные цифры, не помещающиеся в строку консоли. Тем более я приглядел графическую, мультифункциональную библиотеку sfml. Выглядит программа вот так: Основная проблема, с которой я столкнулся, заключалась в том, что для работы с шиной SPI на Raspberry требуются права root, которые нельзя дать программе в графической оболочке. Но спустя некоторое время я нашёл решение. Чтобы программа в графической оболочке запускалась под root она должна : пренадлежать пользователю root вежливо попросить эти права. Первое решается таким вот скриптом: Код (Bash): #! /bin/bash sudo chown root:root $1 sudo chmod 6775 $1 (Если хотите единожды использовать его подставте вместо $1 имя вашего исполняемого фаила. Второе: Код (C++): if (setuid(0)==0) { }else{ //printf("\n all is bed"); fail=1; while(1); } Благодаря бесконечному циклу программа не схлопнется при запуске, если вдруг забыт первый пункт. Спойлер: Код графической оболочки Код (C++): /* cd /home/ftp_user/cpp/graf sudo g++ -c graf4.cpp sudo g++ graf4.o -o graf4e -lsfml-graphics -lsfml-window -lsfml-system */ //#include <unistd.h> #include <SFML/Graphics.hpp> #include <SFML/System.hpp> #include <vector> #include <iostream> #include <cstdlib> #include<time.h> #include <fstream> #include <sstream> #include <string> #include <thread> /* * Конфигурация оборудования */ volatile bool up=1; volatile int *general=new volatile int [126]; void strt(void); struct Cand { int x; int y; int angle; }; class Button{ private: int Bmx,Bmy; int x_pos; int y_pos; int x_scale; int y_scale; sf::Font shr; sf::String typ; sf::Color cb; sf::Color ct; public: sf::RectangleShape bot; sf::Text txt; // икс . игрек . размер Button( int x_pos1, int y_pos1 ,int x_scale1, int y_scale1,sf::String typ1, sf::Color cb1, sf::Color ct1 , sf::Font shr1 ){ x_pos= x_pos1; y_pos= y_pos1; x_scale= x_scale1; y_scale= y_scale1; typ= typ1; cb= cb1; cb= cb1; shr=shr1; } void create() { bot.setSize( sf::Vector2f(x_scale,y_scale)); bot.setPosition(x_pos,y_pos); bot.setFillColor(cb); txt.setString(typ); txt.setCharacterSize(20); txt.setFillColor(ct); txt.setFont(shr); txt.setPosition(x_pos+(x_scale/10),y_pos+(y_scale/2)-20); } bool isClick(){ sf::Event sob; if (sob.mouseButton.button == sf::Mouse::Left) { Bmx=int(abs(sob.mouseButton.x)); Bmy=int(abs(sob.mouseButton.y)); } if((Bmx >x_pos && Bmx < ( x_pos+x_scale) )&&(Bmy > y_pos && Bmy < ( y_pos+y_scale) )) { return 1; }else{ return 0; } } void draw( sf::RenderWindow &W ){ W.draw(bot); W.draw(txt); } }; const int per0=50; //20 герц const int per1=100; // sf::Clock gen; // starts the clock int milliss() { float t=gen.getElapsedTime().asMilliseconds(); //float t=gen.getElapsedTime().asMicroseconds(); return (int)abs(t); } //______ГЛАВНАЯ_ФУНКЦИЯ__________ int main() { // stringstream stream; //stream << "sudo ./home/dima/graf/nrf_writer_EXE " ; // разделитель, отделяющий программу от аргумента << "myargument"; // system(stream.str().c_str()); srand(time(NULL)); int last0,last1, last_val=0,st_st=1,size_bar=0; volatile int* val= new volatile int [126]; std::string s; sf::Font font; font.loadFromFile("/home/dima/fonts/arial.ttf"); std::thread thr(strt); thr.detach(); sf::RenderWindow window(sf::VideoMode(1020, 400), "Сканер частот nrf24l01");// x,y // sf::Clock clock; last0=milliss(); last1=milliss(); sf::RectangleShape osh(sf::Vector2f(50, 100)); sf::RectangleShape bar(sf::Vector2f(340, 20)); sf::RectangleShape fon(sf::Vector2f(500, 24)); osh.setSize( sf::Vector2f(100,20)); osh.setPosition(360,200); bar.setPosition(2,228); fon.setPosition(0,226); fon.setFillColor(sf::Color::Yellow); bar.setFillColor(sf::Color::Blue); Button key(600,100,150,80,L"Кнопка",sf::Color(240,30,45), sf::Color(1,70,95),font ); key.create(); while (window.isOpen()) { sf::Event event; if(milliss()-last0>per0){ while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) window.close(); } if(milliss()-last1>per1){ if(up) { val=general; } } sf::RectangleShape *ppd=new sf::RectangleShape [126]; //sf::RectangleShape ppd(sf::Vector2f(50, 100)); for(int n=0;n<126;n++){ ppd[n].setSize( sf::Vector2f(7,1+10*val[n])); ppd[n].setPosition(1+(8*n),170); ppd[n].setRotation(180.f); } // ppd.setPosition(50+(100*n),0); if(st_st){ size_bar=0; st_st=0; } size_bar+=5; bar.setSize( sf::Vector2f(1+size_bar,20)); // Отрисовка окна window.clear(sf::Color::Black); for(int n =0;n<126;n++){window.draw(ppd[n]);} //window.draw(osh); // window.draw(fon); //window.draw(bar); //key.draw(window); window.display(); last0=milliss(); }} return 0; } Спойлер: Код для nrf Код (C++): #include <cstdlib> #include <iostream> #include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <RF24/nRF24L01.h> /* * Подключаем библиотеку для работы с nRF24L01+ */ #include <RF24/RF24.h> /* * Конфигурация оборудования */ #define BCM_PIN 25 #define SPI_DEV 0 #define NUM_CHANNELS 126 /* * Информация о канале */ void strt() { uint8_t values[NUM_CHANNELS]; const int numReps = 100; extern volatile int *general; extern volatile bool up; /* * Создаём объект radio для работы с библиотекой RF24, * указывая номера вывода CE и SPI порта */ if (setuid(0)==0) { //printf("My UID is: %d. My GID is: %d\n \t g", getuid() , getgid()); }else{ //printf("\n all is bed"); while(1); } RF24 radio(BCM_PIN, SPI_DEV); /* * Инициируем работу nRF24L01+ */ radio.begin(); radio.setAutoAck(false); /* * Вход в режиме ожидания */ radio.startListening(); radio.stopListening(); /* * Дамп конфигурации RF для отладки */ //radio.printDetails(); /* * Распечатка заголовка, верхний и нижний разряд */ while (1) { /* * Очистка значений измерений */ memset(values, 0, sizeof(values)); /* * Сканирование всех каналов numReps раз */ for (int k = 0; k < numReps; ++k) { for (int i = 0; i < NUM_CHANNELS; ++i) { /* * Выбор канала */ radio.setChannel(i); /* * Послушать немного */ radio.startListening(); delayMicroseconds(128); radio.stopListening(); /* * Проверка наличия несущей частоты на выбранном канале (частоте). */ if (radio.testCarrier()) { ++values[i]; } } } /* * Распечатка измерения канала в одну шестнадцатеричную цифру */ up=0; for (int i = 0; i < NUM_CHANNELS; ++i) { // printf("%x", min(0xf, (values[i] & 0xf))); general[i]= std::min(0xf, (values[i] & 0xf)); } up=1; } } Компиляция этого добра заслуживает отдельного рассказа. Всё должно быть в отдельной папке! Итак компилируем код для nrf: Код (Bash): g++ -Ofast -Wall -c rfsc.cpp -lrf24 И код графической оболочки: Код (Bash): g++ -c view.cpp И собираем: Код (Bash): g++ *.o -o nrfGUI -lsfml-graphics -lsfml-window -lsfml-system -fopenmp -lrf24 Не забудте про пункт 1! Знаю, что копипастить иногда не удобно, поэтому оставляю фаилы во вложениях.
Всё хорошо, но только не сказано, что ни один чип nRF24 не умеет измерять УРОВЕНЬ сигнала. Только наличие несущей. Поэтому приведённая гистограмма абсолютно бесполезна для анализа уровня зашумленности выбранного канала. Для такой оценки в диапазоне работы Wi-Fi 2.4 ГГц пользуйтесь утилитой inssider
Согласен, но утилита, которую вы рекомендуете доступна только на Windows и ios. Wi-fi есть только на ноутбуках. А вот во всех android смартфонах есть wi-fi и доступные приложения Network Analayzer и analiti. В первом можно ещё ip малины узнать.
Из чего это следует? Если владелец программы не root, а при сборке приложения простым пользователем владелец получившегося исполняемого файла - пользователь, и права на исполнение разрешены владельцу группе и всем остальным. Почему-же тогда его нельзя выполнить с правами супер пользователя? Собрал простой пример, в котором проверяю на запуск от супер пользователя, если запущен от простого пользователя, то форкаю процесс и в дочернем процессе запускаю то-же приложение уже от супер пользователя. В приложении запущенном с правами супер пользователя в графическом окне отображаю PID Спойлер: test-sfml.cpp Код (C): #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <SFML/Graphics.hpp> int main(int argc, char** argv) { if (getuid() != 0) { pid_t pid; if ((pid = fork()) == 0) { char* args[] = { "/usr/bin/sudo", "/home/alex/test-sfml", NULL }; execve(args[0], args, environ); } else { waitpid(pid, NULL, 0); } } else { // Это тестовый код для отображения графики char tmp[64]; sprintf(tmp, "My pid: %d", getpid()); sf::RenderWindow window(sf::VideoMode(200, 48), "SFML test"); sf::Font font; font.loadFromFile("/home/alex/arial.ttf"); sf::Text text; text.setFont(font); text.setString(tmp); text.setCharacterSize(24); text.setFillColor(sf::Color::Red); text.setPosition(10, 16); window.draw(text); window.display(); while (window.isOpen()) { sf::Event event; while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) { window.close(); } } } } return 0; } Смотрю в процессах владельца этого процесса. Код (Text): alex@rpi3b:~$ ps -fp 5309 UID PID PPID C STIME TTY TIME CMD root 5309 5308 99 16:55 pts/0 00:00:45 /home/alex/test-sfml
Правда на малине я пользуюсь изменением прав на самом устройстве (просто на вскидку): Код (Bash): chmod 777 /dev/i2c-1 chmod 777 /dev/ttyUSB0 chmod 777 /dev/video0 прописав в /etc/rc.local. На устройстве я не "засекречиваю" доступ. Но можно и добавлением в группу пользователя. Мне удобнее первое.
Я добавлял, там похоже сама библиотека требует, чтобы процесс был запущен от root. После моих манипуляций в консоли программа подсвечивается так: