Search
Write a publication
Pull to refresh
2
0

Пользователь

Send message

Настройка BGP для обхода блокировок, или «Как я перестал бояться и полюбил РКН»

Reading time11 min
Views144K

Ну ладно, про «полюбил» — это преувеличение. Скорее «смог сосуществовать с».


Как вы все знаете, с 16 апреля 2018 года Роскомнадзор крайне широкими мазками блокирует доступ к ресурсам в сети, добавляя в "Единый реестр доменных имен, указателей страниц сайтов в сети «Интернет» и сетевых адресов, позволяющих идентифицировать сайты в сети «Интернет», содержащие информацию, распространение которой в Российской Федерации запрещено" (по тексту — просто реестр) по /10 иногда. В результате граждане Российской Федерации и бизнес страдают, потеряв доступ к необходимым им совершенно легальным ресурсам.


После того, как в комментариях к одной из статей на Хабре я сказал, что готов помочь пострадавшим с настройкой схемы обхода, ко мне обратились несколько человек с просьбой о такой помощи. Когда у них всё заработало, один из них порекомендовал описать методику в статье. Поразмыслив, решил нарушить свое молчание на сайте и попробовать в кои-то веки написать что-то промежуточное между проектом и постом в Facebook, т.е. хабрапост. Результат — перед вами.

Читать дальше →

Обход блокировок РКН с помощью DNSTap и BGP

Reading time10 min
Views60K


Тема довольно изъезжена, знаю. К примеру, есть отличная статья, но там рассматривается только IP-часть блоклиста. Мы же добавим еще и домены.


В связи с тем, что суды и РКН блокируют всё направо и налево, а провайдеры усиленно пытаются не попасть под штрафы, выписанные "Ревизорро" — сопутствующие потери от блокировок довольно велики. Да и среди "правомерно" заблокированных сайтов много полезных (привет, rutracker)


Я живу вне юрисдикции РКН, но на родине остались родители, родственники и друзья. Так что было решено придумать легкий для далеких от ИТ личностей способ обхода блокировок, желательно вовсе без их участия.


В этой заметке я не буду расписывать базовые сетевые вещи по шагам, а опишу общие принципы как можно реализовать эту схему. Так что знания как работает сеть вообще и в Linux в частности — must have.

Читать дальше →

Многопоточность в .NET: когда не хватает производительности

Reading time26 min
Views50K


Платформа .NET предоставляет множество готовых примитивов синхронизации и потокобезопасных коллекций. Если при разработке приложения нужно реализовать, например, потокобезопасный кэш или очередь запросов — обычно используются эти готовые решения, иногда сразу несколько. В отдельных случаях это приводит к проблемам с производительностью: долгим ожиданием на блокировках, избыточному потреблению памяти и долгим сборкам мусора.

Эти проблемы можно решить, если учесть, что стандартные решения сделаны достаточно общими — они могут иметь избыточный в наших сценариях оверхед. Соответственно, можно написать, например, собственную эффективную потокобезопасную коллекцию для конкретного случая.

Под катом — видео и расшифровка моего доклада с конференции DotNext, где я разбираю несколько примеров, когда использование средств из стандартной библиотеки .NET (Task.Delay, SemaphoreSlim, ConcurrentDictionary) привело к просадкам производительности, и предлагаю решения, заточенные под конкретные задачи и лишённые этих недостатков.

Обзор ноутбука Dell Latitude 7390: корпоративный супергерой

Reading time8 min
Views56K
Привет, друзья! Совсем недавно мы провели мероприятие, посвященное запуску новых ноутбуков Dell Latitude в России, и сразу же после него одна из «топовых» машин серии оказалась в нашем московском офисе. Мы ее пристально изучили и теперь хотим поделиться с вами подробными впечатлениями от использования. Знакомьтесь: это Latitude 7390, компактный 13-дюймовый лэптоп с процессором Intel Core 8-го поколения, быстрым NVMe SSD, опциональным LTE-модемом, считывателем смарт-карт и хорошей автономностью.


Читать дальше →

Проектирование процессора ModelSim

Reading time17 min
Views17K

Часть I
Часть II
Часть III
Часть IV


Это полная версия предыдущей статьи, к которой добавлены тестбенчи.


Спроектируем Little Man Computer на языке Verilog.


Статья про LMC была на Хабре.


Online симулятор этого компьютера здесь.


Напишем модуль оперативной памяти (ОЗУ), состоящий из четырех (ADDR_WIDTH=2) четырёхбитных (DATA_WIDTH=4) слов. Данные загружаются в ОЗУ из data_in по адресу adr при поступлении тактового сигнала clk.


module R0 #(parameter ADDR_WIDTH = 2, DATA_WIDTH = 4)
(
    input clk, //тактовый сигнал
    input [ADDR_WIDTH-1:0] adr, //адрес
    input [DATA_WIDTH-1:0] data_in, //порт ввода данных
    output [DATA_WIDTH-1:0] RAM_out //порт вывода данных
);
    reg [DATA_WIDTH-1:0] mem [2**ADDR_WIDTH-1:0]; //объявляем массив mem

    always @(posedge clk) //при поступлении тактового сигнала clk 
        mem [adr] <= data_in; //загружаем данные в ОЗУ из data_in 

    assign RAM_out = mem[adr]; //назначаем RAM_out портом вывода данных
endmodule
```<cut/>
В тестбенче загрузим 0001 по адресу 00, 0010 по адресу 01, 0100 по адресу 10, 1000 по адресу 11:
<!--<spoiler title="Создание тестбенча">-->

Создать новый проект, создать файлы R0.v и tR0.v (эти файлы автоматически добавятся к проекту). 
Скомпилировать оба файла.
Запустить моделирование скомпилированного файла tR0.v

<!--</spoiler>-->```verilog
module tR0; 
   reg clk; 
   reg [1:0] adr;
   reg [3:0] data_in;
   wire [3:0] RAM_out;
R0 test_R0 (clk, adr, data_in,RAM_out); 
initial 
   begin
    clk = 0;
    adr[0] = 0;    
    adr[1] = 0;    
    data_in[0] = 0;
    data_in[1] = 0;
    data_in[2] = 0;
    data_in[3] = 0;
    #5 data_in[0] = 1;
    #5 clk = 1;
    #5 adr[0] = 1;  data_in[0] = 0; data_in[1] = 1;  clk = 0;  
    #5 clk = 1;
    #5 adr[0] = 0; adr[1] = 1;  data_in[1] = 0; data_in[2] = 1;  clk = 0;  
    #5 clk = 1;
    #5 adr[0] = 1; adr[1] = 1;  data_in[2] = 0; data_in[3] = 1;  clk = 0;  
        #5 clk = 1;
        #5 adr[0] = 0; adr[1] = 0; data_in[3] = 0;  clk = 0;  
    #5 adr[0] = 1; adr[1] = 0;
    #5 adr[0] = 0; adr[1] = 1;
    #5 adr[0] = 1; adr[1] = 1;
    #5 adr[0] = 0; adr[1] = 0;
    #5 adr[0] = 1; adr[1] = 0;
    #5 adr[0] = 0; adr[1] = 1;
    #5 adr[0] = 1; adr[1] = 1;
    #5 adr[0] = 0; adr[1] = 0;
    #5 adr[0] = 1; adr[1] = 0;
    #5 adr[0] = 0; adr[1] = 1;
    #5 adr[0] = 1; adr[1] = 1;
end
endmodule 


Подключим счётчик к адресному входу ОЗУ. На вход счётчика необходимо подключить тактовый генератор.


Вот пример программы, использующей внутренний генератор ALTUFM_OSC. Частота штатного генератора 5.5 МГц (MAX II EPM240 CPLD Minimal Development Board).


module inner_Clock ( output reg LED);
ALTUFM_OSC osc( .oscena(1'b1), .osc(clk));
   reg signal;
   reg [24:0] osc_counter; 
   reg [24:0] const_data = 25'b10110111000110110000000; 
initial
   begin
      signal = 1'b0;
     osc_counter = 25'b0;
   end
//досчитываем до 6 000 000 и обнуляем счетчик osc_counter
always @(posedge clk)
   begin  
      osc_counter <= osc_counter+ 1'b1;
      if(osc_counter == const_data)
         begin
            signal <= ~signal;
           osc_counter <= 25'b0;
        end
LED = signal; // LED мигает ~1 раз в сеунду.
end
endmodule

Вообще, в данной схеме можно использовать внешний генератор меандра, например КМОП таймер 555 (работающий от 3.3V) или микросхему К155ЛА3 (К155ЛА3 представляет 4 логических элемента 2И-НЕ).


Подключим таймер 555 к счётчику, подключим счётчик к адресному входу ОЗУ.


Теперь при поступлении тактового сигнала на счётчик будет происходить переход на следующую ячейку в памяти. На тактовый вход ОЗУ подключим кнопку RAM_button — данные в ОЗУ будут загружаться при нажатии на эту кнопку.


module R1 (timer555, RAM_button, data_in, RAM_out, counter);
   parameter ADDR_WIDTH = 2;
   parameter DATA_WIDTH = 4;

   input timer555;
   input RAM_button;
   //input [ADDR_WIDTH-1:0] adr;
   input [DATA_WIDTH-1:0] data_in;
   output [DATA_WIDTH-1:0] RAM_out;
   output reg [1:0] counter;
// Counter
always @(posedge timer555) 
  counter <= counter + 1; 
// RAM 
 wire [ADDR_WIDTH-1:0] adr;
 assign adr = counter; 
reg [DATA_WIDTH-1:0] mem [2**ADDR_WIDTH-1:0];
  always @(posedge RAM_button)
     mem [adr] <= data_in;
assign RAM_out = mem[adr];
endmodule

Вот так выглядит схема в RTL Viewer



В симуляторе ModelSim эта схема работать не будет, так как симулятору не известно начальное значение регистров counter[1:0].
Работоспособность схемы можно проверить, непосредственно загрузив программу в ПЛИС.


Далее, добавим в счетчик функцию загрузки. Загрузка из data_in [1:0] производится нажатием на кнопку Counter_load


module R2 (counter, timer555, Counter_load, RAM_button, data_in, RAM_out);
   parameter ADDR_WIDTH = 2;
   parameter DATA_WIDTH = 4;

   output [1:0] counter;
   input timer555, Counter_load;
   // input [N-1:0] adr; 
   input RAM_button;
   input [DATA_WIDTH-1:0] data_in;
   output [DATA_WIDTH-1:0] RAM_out;
// Counter
reg [1:0] counter;
always @ (posedge timer555 or posedge Counter_load)
  if (Counter_load)
       counter <= data_in[1:0];  
  else
     counter <= counter + 2'b01;
// RAM 
 wire [ADDR_WIDTH-1:0] adr;
    assign adr = counter;
reg [DATA_WIDTH-1:0] mem [2**ADDR_WIDTH-1:0]; 
    always @(posedge RAM_button) 
        mem [adr] <= data_in;
assign RAM_out = mem[adr]; 
endmodule

Вот так выглядит подключение кнопок и светодиодов в Pin Planner'е:



Загрузим 0001 по адресу 00, 0010 по адресу 01, 0100 по адресу 10, 1000 по адресу 11


module tR2;
parameter ADDR_WIDTH = 2;
parameter DATA_WIDTH = 4;

reg timer555, Counter_load, RAM_button;
wire [1:0] counter;
reg [DATA_WIDTH-1:0] data_in;
wire [DATA_WIDTH-1:0] RAM_out;

R2 test_R2(counter, timer555, Counter_load, RAM_button, data_in, RAM_out);
initial // Clock generator
  begin
    timer555 = 0;
    forever #20 timer555 = ~timer555;
  end
initial 
  begin
    data_in[0] = 0;
    data_in[1] = 0;
    data_in[2] = 0;
    data_in[3] = 0;
        Counter_load = 0;
    RAM_button = 0;
    #5 data_in[0]=0; data_in[1]=0; Counter_load=1; RAM_button=0; 
        #5 data_in[0]=1; data_in[1]=0; Counter_load=0; RAM_button=1; 
    #5 data_in[0]=0; data_in[1]=0; Counter_load=0; RAM_button=0; 

    #5 data_in[0]=1; data_in[1]=0; Counter_load=1; RAM_button=0; 
    #5 data_in[0]=0; data_in[1]=1; Counter_load=0; RAM_button=1; 
    #5 data_in[0]=0; data_in[1]=0; Counter_load=0; RAM_button=0; 

    #5 data_in[0]=0; data_in[1]=1; Counter_load=1; RAM_button=0; 
    #5 data_in[2]=1; data_in[0]=0; data_in[1]=0; Counter_load=0; RAM_button=1; 
        #5 data_in[2]=0; data_in[0]=0; data_in[1]=0; Counter_load=0; RAM_button=0; 

        #5 data_in[0]=1; data_in[1]=1; Counter_load=1; RAM_button=0; 
    #5 data_in[3]=1; data_in[0]=0; data_in[1]=0; Counter_load=0; RAM_button=1; 
    #5 data_in[3]=0; data_in[0]=0; data_in[1]=0; Counter_load=0; RAM_button=0; 
  end
endmodule    


В отдельном модуле создаем 4bit'ный регистр (аккумулятор).


Данные загружаются в регистр при нажатии на кнопку reg_button:


module register4
(
  input  [3:0] reg_data,
  input reg_button,
  output reg [3:0] q  
);
always @(posedge reg_button)
         q <= reg_data;
endmodule

Добавим в общую схему аккумулятор Acc, мультиплексор MUX2 и сумматор sum.
Сумматор прибавляет к числу в аккумуляторе Acc числа из памяти.
На сигнальные входы мультиплексора подаются числа data_in и sum.
Число из MUX2 загружается в аккумулятор Acc при нажатии кнопки Acc_button.
Число из Асс загружается в ОЗУ при нажатии кнопки RAM_button.




module R3 (MUX_switch, Acc_button, Acc, counter, timer555, 
                 Counter_load, RAM_button, data_in, RAM_out);
   parameter ADDR_WIDTH = 2;
   parameter DATA_WIDTH = 4;

   input MUX_switch;
   input Acc_button; 
   output [3:0] Acc;

   input timer555, Counter_load;
   output [1:0] counter;
   // input [N-1:0] adr; 
   input RAM_button;
   input [DATA_WIDTH-1:0] data_in;
   output [DATA_WIDTH-1:0] RAM_out;
// Counter
reg [1:0] counter;
always @ (posedge timer555 or posedge Counter_load)
  if (Counter_load)
       counter <= data_in[1:0];  
  else
     counter <= counter + 2'b01;
// RAM 
 wire [ADDR_WIDTH-1:0] adr;
    assign adr = counter;
reg [DATA_WIDTH-1:0] mem [2**ADDR_WIDTH-1:0]; 
    always @(posedge RAM_button) 
        mem [adr] <= Acc;
assign RAM_out = mem[adr];
// sum 
wire [3:0] sum;
assign sum =  Acc + RAM_out;
// MUX2
reg [3:0] MUX2; 
always @*
MUX2 = MUX_switch ? sum : data_in;
//Схема подавления дребезга контактов кнопки Acc_button
/* reg Acc_dff;
always @(posedge Acc_button or negedge timer555)
        if (!timer555)
            Acc_dff <= 1'b0;
        else
            Acc_dff <= timer555;  */
//Acc
register4 Acc_reg(
    .reg_data(MUX2),
        //.reg_button(Acc_dff),
    .reg_button(Acc_button),
    .q(Acc)
);
endmodule

Для программного подавления дребезга можно применить простую схему


/* reg Acc_dff;
always @(posedge Acc_button or negedge timer555)
if (!timer555)
Acc_dff <= 1'b0;
else
Acc_dff <= timer555; */

А можно использовать одновибратор (ждущий мультивибратор), собранный на таймере 555 или микросхеме К155ЛА3


Далее, будем складывать числа, например, 2 и 3.


  1. Загружаем числа в ОЗУ
  2. Обнуляем Асс
  3. Переключаем MUX2
  4. Загружаем первое число из ОЗУ в Асс
  5. Прибавляем к числу в Асс второе число из ОЗУ
  6. Загружаем сумму в ОЗУ
    module tR3;
    parameter ADDR_WIDTH = 2;
    parameter DATA_WIDTH = 4;
      reg MUX_switch;
      reg Acc_button; 
      wire [3:0] Acc;
      reg timer555, Counter_load, RAM_button;
      wire [1:0] counter;
      reg [DATA_WIDTH-1:0] data_in;
      wire [DATA_WIDTH-1:0] RAM_out;
    R3 test_R3(MUX_switch, Acc_button, Acc, counter, timer555, 
                Counter_load, RAM_button, data_in, RAM_out);
    initial 
    begin
    timer555 = 0;
    forever #20 timer555 = ~timer555;
    end
    initial 
    begin
    data_in[0] = 0;
    data_in[1] = 0;
    data_in[2] = 0;
    data_in[3] = 0;
    Counter_load = 0;
    Acc_button = 0;
    RAM_button = 0;
    MUX_switch = 0;
    #5 Counter_load = 1;
    #5 data_in[0]=0; data_in[1]=1; Counter_load = 0;
    #5 Acc_button = 1;  
    #5 RAM_button = 1;  
    #5 data_in[0]=0; data_in[1] = 0; Acc_button = 0; RAM_button = 0; 
    #5 data_in[0]=1; data_in[1]=1;
    #15 Acc_button = 1;
    #5 RAM_button = 1;
    #5 Acc_button = 0;
    #5 data_in[0]=0; data_in[1] = 0; RAM_button = 0;
    #10 Acc_button = 1;
    #10 Acc_button = 0;
    #60 MUX_switch = 1; 
    #10 Acc_button = 1;
    #10 Acc_button = 0;
    #30 Acc_button = 1;
    #10 Acc_button = 0;
    #30 RAM_button = 1;
    #10 RAM_button = 0;
    end
    endmodule    


Добавим в основной модуль элемент, вычитающий из числа в аккумуляторе число, записанное в памяти.


wire [3:0] subtract;
assign subract =  Acc - RAM_out ;

Заменим двухвходовой мультиплексор 4х_входовым```verilog
always @*
MUX4 = MUX_switch[1]? (MUX_switch[0]? RAM_out: subtract)
: (MUX_switch[0]? sum: data_in);


Подключим к аккумулятору устройство вывода (4bit'ный регистр), также подключим к аккумулятору  2 флага:

1. Флаг "Ноль" - это лог. элемент 4ИЛИ-НЕ.  Флаг поднимается, если содержимое Асс равно нулю. 

2. Флаг "Ноль или Положительное число" - это лог. элемент НЕ на старшем разряде четырёхразрядного аккумулятора. Флаг поднимается, если содержимое Асс больше или равно нулю.
```verilog
//флаг "Ноль" 
output Z_flag;
assign Z_flag =  ~(|Acc); // многовходовой вентиль ИЛИ
//флаг "Ноль или Положительное число"
output PZ_flag;
assign PZ_flag =  ~Acc[3]; 


Добавим три команды


  1. загрузка содержимого аккумулятора в устройство вывода data_out


  2. загрузка адреса в счётчик, если поднят флаг "ноль" (JMP if Acc=0)


  3. загрузка адреса в счётчик, если поднят флаг "ноль или положительное число" (JMP if Acc>=0)


    module R4 (JMP,Z_JMP,PZ_JMP,Z_flag,PZ_flag,Output_button,data_out,MUX_switch,Acc_button,Acc,counter,timer555,RAM_button,data_in,RAM_out);
    parameter ADDR_WIDTH = 2;
    parameter DATA_WIDTH = 4;
    
    input JMP, Z_JMP, PZ_JMP;
    output Z_flag, PZ_flag;
    input Output_button;
    output [3:0] data_out;
    input [1:0] MUX_switch;
    input Acc_button; 
    output [3:0] Acc;
    input timer555; 
    output [1:0] counter;
    input RAM_button;
    input [DATA_WIDTH-1:0] data_in;
    output [DATA_WIDTH-1:0] RAM_out;
    // flags
    wire Z,PZ;
    assign Z = Z_flag & Z_JMP;
    assign PZ = PZ_flag & PZ_JMP;   
    // Counter
    reg [1:0] counter;
    always @ (posedge timer555 or posedge JMP or posedge Z or posedge PZ)
    if (JMP|Z|PZ)
       counter <= data_in[1:0];  
    else
     counter <= counter + 2'b01;
    // RAM 
    wire [ADDR_WIDTH-1:0] adr;
    assign adr = counter;
    reg [DATA_WIDTH-1:0] mem [2**ADDR_WIDTH-1:0]; 
    always @(posedge RAM_button) 
        mem [adr] <= Acc;
    assign RAM_out = mem[adr];
    // sum 
    wire [3:0] sum;
    assign sum =  Acc + RAM_out;
    //subtract
    wire [3:0] subtract;
    assign subtract =  Acc - RAM_out;
    // MUX4
    reg [3:0] MUX4; 
    always @*
    MUX4 = MUX_switch[1] ? (MUX_switch[0] ? RAM_out : subtract)
    : (MUX_switch[0] ? sum : data_in);
    //Acc
    register4 Acc_reg(
    .reg_data(MUX4),
    .reg_button(Acc_button),
    .q(Acc)
    );
    //data_out
    register4 Output_reg(
    .reg_data(Acc),
    .reg_button(Output_button),
    .q(data_out)
    );
    assign Z_flag =  ~(|Acc);
    assign PZ_flag =  ~Acc[3];
    endmodule


  4. Загружаем числа в ОЗУ


  5. Обнуляем Асс


  6. Переключаем MUX2


  7. Вычитаем первое число (записанное в ОЗУ) из Асс


  8. Вычитаем второе число (записанное в ОЗУ) из Асс


  9. Загружаем сумму в ОЗУ и в data_out


    
    module tR4;
    parameter ADDR_WIDTH = 2;
    parameter DATA_WIDTH = 4;
    reg JMP, Z_JMP, PZ_JMP;
    wire Z_flag, PZ_flag;
    reg Output_button;
    wire [3:0] data_out;
    reg [1:0] MUX_switch;
    reg Acc_button; 
    wire [3:0] Acc;
    reg timer555, RAM_button;
    wire [1:0] counter;
    reg [DATA_WIDTH-1:0] data_in;
    wire [DATA_WIDTH-1:0] RAM_out;


R4 test_R4
(JMP,Z_JMP,PZ_JMP,Z_flag,PZ_flag,Output_button,data_out,MUX_switch,Acc_button,Acc,
counter,timer555,RAM_button,data_in,RAM_out);
initial
begin
timer555 = 0;
forever #20 timer555 = ~timer555;
end
initial
begin
data_in[0] = 0;
data_in[1] = 0;
data_in[2] = 0;
data_in[3] = 0;
JMP = 0; Z_JMP = 0; PZ_JMP = 0;
Acc_button = 0;
RAM_button = 0;
Output_button = 0;


MUX_switch[0] = 0;
MUX_switch[1] = 0;
    #5 JMP = 1;
#5 data_in[0]=0; data_in[1]=1; JMP = 0;
#5 Acc_button = 1;  
#5 RAM_button = 1;  
#5 data_in[0]=0; data_in[1] = 0; Acc_button = 0; RAM_button = 0; 
#5 data_in[0]=1; data_in[1]=1;
#15 Acc_button = 1;
#5 RAM_button = 1;
#5 Acc_button = 0;
#5 data_in[0]=0; data_in[1] = 0; RAM_button = 0;
#10 Acc_button = 1;
#10 Acc_button = 0;
#60 MUX_switch[1] = 1; 
#10 Acc_button = 1;
#10 Acc_button = 0;
#30 Acc_button = 1;
#10 Acc_button = 0;
#30 RAM_button = 1; Output_button = 1;
#10 RAM_button = 0; Output_button = 0;

end
endmodule


<img src="https://habrastorage.org/webt/jb/fq/c4/jbfqc45piovx4besdmw0pkxz_oa.gif" />

Проверим, что когда в Асс лежит положительное число, перехода Z_JMP не происходит:
```verilog
module tR4_jmp;
parameter ADDR_WIDTH = 2;
parameter DATA_WIDTH = 4;

   reg JMP, Z_JMP, PZ_JMP;
   wire Z_flag, PZ_flag;
   reg Output_button;
   wire [3:0] data_out;
   reg [1:0] MUX_switch;
   reg Acc_button; 
   wire [3:0] Acc;
   reg timer555, RAM_button;
   wire [1:0] counter;
   reg [DATA_WIDTH-1:0] data_in;
   wire [DATA_WIDTH-1:0] RAM_out;
R4 test_R4
(JMP,Z_JMP,PZ_JMP,Z_flag,PZ_flag,Output_button,data_out,MUX_switch,Acc_button,Acc,
counter,timer555,RAM_button,data_in,RAM_out);
initial 
  begin
    timer555 = 0;
    forever #20 timer555 = ~timer555;
  end
initial 
  begin
    data_in[0] = 0;
    data_in[1] = 0;
    data_in[2] = 0;
    data_in[3] = 0;
        JMP = 0; Z_JMP = 0; PZ_JMP = 0;
    Acc_button = 0;
    RAM_button = 0;
    Output_button = 0;

    MUX_switch[0] = 0;
    MUX_switch[1] = 0;
        #5 JMP = 1;
    #5 data_in[0]=0; data_in[1]=1; JMP = 0;
    #5 Acc_button = 1;  
    #5 data_in[0]=1; data_in[1]=1; Acc_button = 1;  
    #5 data_in[0]=1; data_in[1]=1; Acc_button = 0;  
    #5 Z_JMP = 1;
    #5 PZ_JMP = 1; Z_JMP = 0;
    #5 PZ_JMP = 0; 
  end
endmodule    


Поместим команду безусловного перехода в ОЗУ



Конструкция вида


//wire Counter_load;
always @ (posedge timer555)
  if (Counter_load)
       counter <= RAM_out[3:0];  
  else
     counter <= counter + 2'b01;

в ModelSim работать не будет, поэтому будем использовать дополнительную команду reset_count, которая инициализирует счетчик, обнуляя его, т.е.


module resCount (reset_count, counter, timer555, 
                         RAM_button, data_in, RAM_out);
   parameter ADDR_WIDTH = 4;
   parameter DATA_WIDTH = 8;

  input reset_count;
  output [ADDR_WIDTH-1:0] counter;
  input timer555;
  input RAM_button;
  input [DATA_WIDTH-1:0] data_in;
  output [DATA_WIDTH-1:0] RAM_out;
wire Counter_load;
assign Counter_load = RAM_out[7];
reg [ADDR_WIDTH-1:0] counter;
always @ (posedge timer555 or posedge reset_count)
  if (reset_count)
        counter <= 4'b0000;  
  else if (Counter_load) 
        counter <= RAM_out[3:0];  
  else
        counter <= counter + 4'b0001;
 wire [ADDR_WIDTH-1:0] adr;
    assign adr = counter;
reg [DATA_WIDTH-1:0] mem [2**ADDR_WIDTH-1:0]; 
    always @(posedge RAM_button) 
        mem [adr] <= data_in;
assign RAM_out = mem[adr]; 
endmodule

test bench


module tresCount;
   parameter ADDR_WIDTH = 4;
   parameter DATA_WIDTH = 8;

   reg reset_count; 
   reg timer555, RAM_button;
   wire [ADDR_WIDTH-1:0] counter;
   reg [DATA_WIDTH-1:0] data_in;
   wire [DATA_WIDTH-1:0] RAM_out;
resCount test_resCount(reset_count, counter, 
                                 timer555, RAM_button, data_in, RAM_out);
initial // Clock generator
  begin
    timer555 = 0;
    forever #20 timer555 = ~timer555;
  end
initial 
  begin
    data_in[0] = 0;
    data_in[1] = 0;
    data_in[2] = 0;
    data_in[3] = 0;
    data_in[4] = 0;
    data_in[5] = 0;
    data_in[6] = 0;
    data_in[7] = 0;
    RAM_button = 0;
    reset_count =1;
    #5 reset_count =0;
    #1500 data_in[7] =1;
    #5 RAM_button = 1;
    #5 data_in[7] =0; RAM_button = 0;
  end
endmodule    


Добавим в схему MUX2 и Асс. Будем производить запись в Асс командой RAM_out[6].


assign Acc_button = RAM_out[6];

К тактовому входу Асс подключим лог. элемент И


//в модуле regiser4 заменим (posedge reg_button) на (negedge reg_button)
.reg_button(Acc_button & timer555),

Смысл подключения лог. элемента И к тактовому входу в том, что теперь по фронту timer555 можно переключать мультиплексор, а по спаду производить запись в аккумулятор. Т.о. мы поместили две команды в один такт.


Будем производить переключение MUX2 командой RAM_out[5]


assign MUX_switch = RAM_out[5];


module register4
(
  input  [3:0] reg_data,
  input reg_button,
  output reg [3:0] q  
);
always @(negedge reg_button) // заменим "posedge" на  "negedge"
         q <= reg_data;
endmodule

module R50 (reset_count, counter, timer555, RAM_button, data_in, 
                  RAM_out, mux_switch_out, mux_out,Acc_out);
   parameter ADDR_WIDTH = 2;
   parameter DATA_WIDTH = 8;

  input reset_count;
  output [ADDR_WIDTH-1:0] counter;
  input timer555;
  input RAM_button;
  input [DATA_WIDTH-1:0] data_in;
  output [DATA_WIDTH-1:0] RAM_out;
  output [3:0] Acc_out;

  output mux_switch_out;
  output [3:0] mux_out;
wire Counter_load;
assign Counter_load = RAM_out[7];
//Counter
reg [ADDR_WIDTH-1:0] counter;
always @ (posedge timer555 or posedge reset_count)
  if (reset_count)
        counter <= 2'b00;  
  else if (Counter_load) 
        counter <= RAM_out[1:0];  
  else
        counter <= counter + 2'b01;

wire [ADDR_WIDTH-1:0] adr;
 assign adr = counter;
//RAM
reg [DATA_WIDTH-1:0] mem [2**ADDR_WIDTH-1:0]; 
    always @(posedge RAM_button) 
        mem [adr] <= data_in;
assign RAM_out = mem[adr]; 
// MUX2
wire MUX_switch;
assign MUX_switch = RAM_out[5];
reg [3:0] MUX2; 
always @*
MUX2 = MUX_switch ? RAM_out : data_in[3:0]; // возьмём 4 разряда из data_in
assign mux_out = MUX2;
assign mux_switch_out = MUX_switch;

wire Acc_button;
assign Acc_button = RAM_out[6];
//Acc
register4 Acc_reg(
    .reg_data(mux_out),
    .reg_button(Acc_button & timer555),
    .q(Acc_out)
);
endmodule

В тестбенче запишем в ячейку 00 число 0101, а в ячейку 01 число 1010; загрузим эти числа в аккумулятор


module tR50;
   parameter ADDR_WIDTH = 2;
   parameter DATA_WIDTH = 8;

   reg reset_count; 
   reg timer555, RAM_button;
   wire [ADDR_WIDTH-1:0] counter;
   reg [DATA_WIDTH-1:0] data_in;
   wire [DATA_WIDTH-1:0] RAM_out;

   wire mux_switch_out;
   wire [3:0] mux_out;
   wire [3:0] Acc_out;
R50 test_R50(reset_count, counter, timer555, RAM_button, data_in, 
                  RAM_out, mux_switch_out, mux_out,Acc_out);
initial // Clock generator
  begin
    timer555 = 0;
    forever #20 timer555 = ~timer555;
  end
initial 
  begin
  data_in[0] = 1;
  data_in[1] = 0;
  data_in[2] = 1;
  data_in[3] = 0;
  data_in[4] = 0;
  data_in[5] = 1;
  data_in[6] = 1;
  data_in[7] = 0;
  RAM_button = 0;
  reset_count =1;  
  #5 RAM_button = 1; reset_count = 0; 
  #5 data_in[0]=0; data_in[2]=0; data_in[5]=0; data_in[6]=0; RAM_button=0;
  #15 data_in[1]=1; data_in[3]=1; data_in[5]=1;data_in[6]=1;
  #5 RAM_button=1; 
  #5 data_in[1]=0; data_in[3]=0; data_in[5]=0; data_in[6]=0; RAM_button=0; 
  end
endmodule    


Поместим второе ОЗУ в общую схему и будем производить запись в ОЗУ командой RAM1_out[4].


assign RAM2_button = RAM1_out[4];


module register4
(
  input  [3:0] reg_data,
  input reg_button,
  output reg [3:0] q  
);
always @(negedge reg_button) 
         q <= reg_data;
endmodule

module R51 (reset_count, counter, timer555, RAM1_button, data_in, 
            RAM1_out, RAM2_out, mux_switch_out, mux_out,Acc_out);
   parameter ADDR_WIDTH = 3;
   parameter DATA_WIDTH = 8;

  input reset_count;
  output [ADDR_WIDTH-1:0] counter;
  input timer555;
  input RAM1_button;
  input [DATA_WIDTH-1:0] data_in;
  output [DATA_WIDTH-1:0] RAM1_out;
  output [3:0] RAM2_out;
  output [3:0] Acc_out;

  output mux_switch_out;
  output [3:0] mux_out;
wire Counter_load;
assign Counter_load = RAM1_out[7];
//Counter
reg [ADDR_WIDTH-1:0] counter;
always @ (posedge timer555 or posedge reset_count)
  if (reset_count)
        counter <= 2'b00;  
  else if (Counter_load) 
        counter <= RAM1_out[1:0];  
  else
        counter <= counter + 2'b01;

wire [ADDR_WIDTH-1:0] adr1;
 assign adr1 = counter;
//RAM1
reg [DATA_WIDTH-1:0] mem1 [2**ADDR_WIDTH-1:0]; 
    always @(posedge RAM1_button ) 
        mem1 [adr1] <= data_in;
assign RAM1_out = mem1[adr1]; 

wire [ADDR_WIDTH-1:0] adr2;
 assign adr2 = RAM1_out[3:0];
wire RAM2_button;
   assign RAM2_button = RAM1_out[4];
//RAM2
reg [3:0] mem2 [2**ADDR_WIDTH-1:0]; 
always @(posedge RAM2_button)
   mem2 [adr2] <= Acc_out;
assign RAM2_out = mem2[adr2]; 
// MUX2
wire MUX_switch;
 assign MUX_switch = RAM1_out[5];
reg [3:0] MUX2; 
always @*
MUX2 = MUX_switch ? RAM2_out : data_in[3:0];
assign mux_out = MUX2;
assign mux_switch_out = MUX_switch;

wire Acc_button;
assign Acc_button = RAM1_out[6];
//Acc
register4 Acc_reg(
   .reg_data(mux_out),
   .reg_button(Acc_button & timer555),
   .q(Acc_out)
);
endmodule

В тестбенче загрузим числа 0100 и 1000 из Асс в нулевую 0000 и первую 0001 ячейки ОЗУ mem2 (затем загрузим эти числа в Асс из ОЗУ mem2)


module tR51;
   parameter ADDR_WIDTH = 3;
   parameter DATA_WIDTH = 8;

   reg reset_count; 
   reg timer555, RAM1_button;
   wire [ADDR_WIDTH-1:0] counter;
   reg [DATA_WIDTH-1:0] data_in;
   wire [DATA_WIDTH-1:0] RAM1_out;
   wire [3:0] RAM2_out;

   wire mux_switch_out;
   wire [3:0] mux_out;
   wire [3:0] Acc_out;
R51 test_R51(reset_count, counter, timer555, RAM1_button, data_in, 
             RAM1_out, RAM2_out, mux_switch_out, mux_out,Acc_out);
initial // Clock generator
  begin
    timer555 = 0;
    forever #20 timer555 = ~timer555;
  end
initial 
  begin
  data_in[0] = 0;
  data_in[1] = 0;
  data_in[2] = 0;
  data_in[3] = 0;
  data_in[4] = 0;
  data_in[5] = 0;
  data_in[6] = 1;
  data_in[7] = 0;
  RAM1_button = 0;
  reset_count =1;  
  #5 RAM1_button = 1; reset_count = 0;  
  #5 RAM1_button = 0; data_in[6] = 0;

  #10 data_in[4] = 1; 
  #5 RAM1_button = 1;
  #5 data_in[4] = 0; RAM1_button = 0;

  #30 data_in[6] = 1; 
  #5 RAM1_button = 1; 
  #5 data_in[6] = 0; RAM1_button = 0;

  #30  data_in[4] = 1;     data_in[0] = 1; 
  #5 RAM1_button = 1;
  #5 data_in[4] = 0; data_in[0] = 0; RAM1_button = 0;

  #30 data_in[6] = 1; 
  #5 RAM1_button = 1;
  #5  RAM1_button = 0; data_in[6] = 0;

  #30 data_in[5] = 1; data_in[6] = 1;
  #5 RAM1_button = 1;
  #5  RAM1_button = 0; data_in[5] = 0; data_in[6] = 0;

  #30 data_in[5] = 1; data_in[6] = 1; data_in[0] = 1;
  #5 RAM1_button = 1;
  #5 RAM1_button = 0; data_in[0] = 0; data_in[5] = 0; data_in[6] = 0;

  #70 data_in[2] = 1;
  #80 data_in[2] = 0; data_in[3] = 1;
  #40 data_in[3] = 0;
  end
endmodule    


Добавлю, что схема c лог. элементом И на тактовом входе аккумулятора не всегда будет работать корректно (зависит от платы). Заменим лог. элемент И на триггер Acc_dff, загрузку в триггер будем производить по отрицательному фронту (по спаду) тактового сигнала timer555, загрузку в аккумулятор будем производить по положительному фронту


// Acc_dff
reg Acc_dff;
always @(negedge timer555)
        Acc_dff <= Acc_button;  

Итак, добавив остальные команды, создадим модуль R52 (LMC)



module register4
(
  input  [3:0] reg_data,
  input reg_button,
  output reg [3:0] q  
);
always @(posedge reg_button) // negedge -> posedge
         q <= reg_data;
endmodule

module R52 (Z_flag, PZ_flag, reset_count, counter, timer555, RAM1_button, data_in, 
           RAM1_out, RAM2_out, mux_switch_out, mux_out, Acc_out, data_out, Acc_dff);
  parameter ADDR_WIDTH = 4;
  parameter DATA_WIDTH = 12;

  input reset_count;
  input timer555;
  input RAM1_button;
  input [DATA_WIDTH-1:0] data_in;

  output [ADDR_WIDTH-1:0] counter;
  output [1:0] mux_switch_out;
  output [3:0] mux_out;
  output [3:0] Acc_out;
  output [3:0] data_out;
  output [DATA_WIDTH-1:0] RAM1_out;
  output [3:0] RAM2_out;
  output Z_flag, PZ_flag;
  output Acc_dff;

wire JMP_button, Z_JMP_button,PZ_JMP_button;
  assign JMP_button = RAM1_out[6];
  assign Z_JMP_button = RAM1_out[5];
  assign PZ_JMP_button = RAM1_out[4];   

wire Z_JMP,PZ_JMP;
 assign Z_JMP = Z_flag & Z_JMP_button;
 assign PZ_JMP = PZ_flag & PZ_JMP_button;   

//Counter
reg [ADDR_WIDTH-1:0] counter;
 always @ (posedge timer555 or posedge reset_count)
  if (reset_count)
        counter <= 4'b0000;  
  else if (JMP_button|Z_JMP|PZ_JMP)
        counter <= RAM1_out[3:0];  
  else
        counter <= counter + 4'b0001;

wire [ADDR_WIDTH-1:0] adr1;
 assign adr1 = counter;
//RAM1
reg [DATA_WIDTH-1:0] mem1 [2**ADDR_WIDTH-1:0]; 
    always @(posedge RAM1_button ) 
        mem1 [adr1] <= data_in;
 assign RAM1_out = mem1[adr1]; 
//RAM2_adr
wire [ADDR_WIDTH-1:0] adr2;
   assign adr2 = RAM1_out[2:0];
//RAM2_button
wire RAM2_button;
   assign RAM2_button = RAM1_out[11];
//RAM2  
reg [3:0] mem2 [2**ADDR_WIDTH-1:0]; 
    always @(posedge RAM2_button) 
         mem2 [adr2] <= Acc_out;
 assign RAM2_out = mem2[adr2];        
// sum 
wire [3:0] sum;
 assign sum =  Acc_out + RAM2_out;
//subtract
wire [3:0] subtract;
 assign subtract =  Acc_out - RAM2_out;
// MUX4
wire [1:0] mux_switch;
 assign mux_switch[0] = RAM1_out[7];
 assign mux_switch[1] = RAM1_out[8];
reg [3:0] MUX4; 
always @*
MUX4 = mux_switch[1] ? (mux_switch[0] ? RAM2_out : subtract)
: (mux_switch[0] ? sum : data_in[3:0]);

 assign mux_out = MUX4;
 assign mux_switch_out[0] = mux_switch[0];
 assign mux_switch_out[1] = mux_switch[1];
//Acc_button
wire Acc_button;
 assign Acc_button = RAM1_out[10];
// Acc_dff
reg Acc_dff;
always @(negedge timer555)
   Acc_dff <= Acc_button;  
//Acc
register4 Acc_reg(
    .reg_data(mux_out),
     //.reg_button(Acc_button & timer555),
    .reg_button(Acc_dff),
    .q(Acc_out)
);
//data_out
wire Output_button;
 assign Output_button = RAM1_out[9];
register4 Output_reg(
    .reg_data(Acc_out),
    .reg_button(Output_button),
    .q(data_out)
);
// flags
 assign Z_flag =  ~(|Acc_out);
 assign PZ_flag =  ~Acc_out[3];
endmodule

В тестбенче проверим, как работает алгоритм поиска максимального числа.


Особенность загрузки команд в ОЗУ заключается в том, что после загрузки всех команд нам приходится возвращаться (340ns) в ячейку 8 и загружать ещё одну команду


module tR52;
   parameter ADDR_WIDTH = 4;
   parameter DATA_WIDTH = 12;

  reg reset_count;
  reg timer555;
  reg RAM1_button;
  reg [DATA_WIDTH-1:0] data_in;

  wire [ADDR_WIDTH-1:0] counter;
  wire [1:0]mux_switch_out;
  wire [3:0] mux_out;
  wire [3:0] Acc_out;
  wire [3:0] data_out;
  wire [DATA_WIDTH-1:0] RAM1_out;
  wire [3:0] RAM2_out;
  wire Z_flag, PZ_flag;
  wire Acc_dff;

R52 test_R52(Z_flag, PZ_flag, reset_count, counter, timer555, RAM1_button, data_in,
    RAM1_out, RAM2_out, mux_switch_out, mux_out,Acc_out, data_out, Acc_dff);
initial // Clock generator
  begin
    timer555 = 0;
    forever #20 timer555 = ~timer555;
  end

initial 
  begin
  data_in[0] = 0;
  data_in[1] = 0;
  data_in[2] = 0;
  data_in[3] = 0;
  data_in[4] = 0;
  data_in[5] = 0;
  data_in[6] = 0;
  data_in[7] = 0;
  data_in[8] = 0;
  data_in[9] = 0;
  data_in[10] = 1;
  data_in[11] = 0;
  RAM1_button = 0;
  reset_count =1;  
  // загружаем 1-ое число в Асс
  #5 RAM1_button = 1; reset_count = 0;  
  #5 RAM1_button = 0; data_in[10] = 0; data_in[0] = 0;
  // сохраняем 1-ое число в ячейке 0
  #10 data_in[11] = 1; 
  #5 RAM1_button = 1;
  #5 data_in[11] = 0; RAM1_button = 0;
  // загружаем 2-ое число в Асс
  #30 data_in[10] = 1;  
  #5 RAM1_button = 1; 
  #5 RAM1_button = 0; data_in[10] = 0;  
   // сохраняем 2-ое число в ячейке 0
  #30 data_in[11] = 1;data_in[0] = 1; 
  #5 RAM1_button = 1;
  #5 data_in[11] = 0;data_in[0] = 0; RAM1_button = 0;
   //вычитаем 1-ое число из Асс
  #30 data_in[8]=1; data_in[10] = 1;  
  #5 RAM1_button = 1; 
  #5 RAM1_button = 0;  data_in[8]=0; data_in[10] = 0;  
   // Если Acc>=0, переходим на ячейку 8
  #30 data_in[4]=1;   data_in[3]=1;  
  #5 RAM1_button = 1; 
  #5 RAM1_button = 0;  data_in[4]=0; data_in[3]=0; 
  // загружаем 1-ое число
  #30 data_in[7] = 1; data_in[8] = 1;   data_in[10] = 1;  
  #5 RAM1_button = 1; 
  #5 RAM1_button = 0; data_in[7] = 0; data_in[8] = 0; data_in[10] = 0;  
  // безусловный переход в ячейку 9
  #30 data_in[6] = 1; data_in[3]=1; data_in[0]=1;   
  #5 RAM1_button = 1; 
  #5 RAM1_button = 0; data_in[6] = 0;  data_in[3]=0; data_in[0]=0;  
   //выводим число в data_out
  #30 data_in[9] = 1;
  #5 RAM1_button = 1; 
  #5 RAM1_button = 0; data_in[9] = 0;  
  // безусловный переход в ячейку 8
  #30 data_in[6] = 1; data_in[3]=1; data_in[0]=0;  
  #5 RAM1_button = 1; 
  #5 RAM1_button = 0; data_in[6] = 0;  data_in[3]=0; data_in[0]=0;  
  //загружаем 2-ое число
  #30 data_in[7] = 1; data_in[8] = 1;   data_in[10] = 1; data_in[0] = 1; 
  #5 RAM1_button = 1; 
  #5 RAM1_button = 0; data_in[7] = 0; data_in[8] = 0; data_in[10] = 0; data_in[0] = 0;

  #75 RAM1_button = 1;
  #5 RAM1_button = 0;

  #230 data_in[2]=1;  data_in[0]=0; //первое число
  #80 data_in[2]=0; data_in[0]=1; // второе число
 end
endmodule    

Ссылка на github с кодами программ.


Бесплатную студенческую версию ModelSim под Windows можно скачать с сайта www.model.com.
Далее необходимо (заполнив форму) скачать файл student_license.dat и поместить этот файл в основную директорию программы ModelSim.


Ссылка на файл ModelSim под Linux (Ubuntu) здесь
Инструкция по установке здесь.

Пневмоника и влажные мечты стимпанка

Reading time13 min
Views66K
“Пневмоавтоматика с каждым годом приобретает все большее значение для современной техники. Пневматические приборы широко применяются при автоматизации производственных процессов и при управлении энергетическими установками”

Л.А.Залманзон Пневмоника. Струйная пневмоавтоматика. изд. Наука, М. 1965


Рисунок 1: Fluidic Kit by Tekniska musee


Допустим мы решили забить на сборку компьютера на герконовых реле и заняться еще более безумными вещами. Для тех, кто следит за сборкой BrainfuckPC — не пугайтесь, ему ничего не угрожает. Я лишь строю планы на будущее.


Введение


Знаете ли вы что такое эффект прилипания струи к стенке? Пройдемся ка с вами в ванную, предварительно захватив с собой столовую ложку:



Рисунок 2: Эффект прилипания струи


Мы видим, как струя воды соприкоснувшись с горбом ложки тут же прилипает к ее стенке, заметно искривляясь. Это явление известно давно и описывалось многими исследователями, в том числе такими видными как Юнг и Рейнольдс. Свое название “Эффект Коанда”, однако это явление получило по имени работавшего во Франции румынского изобретателя Анри Коанда, который в начале прошлого века предложил использовать его для ряда технических приложений.

Бесплатное программное обеспечение для IP-камер

Reading time5 min
Views814K
За 11 лет работы на рынке видеонаблюдения, нам пришлось столкнутся с множеством программ для управления системами видеонаблюдения, с какими-то мы работали, какие то тестировали, какие хотели потестировать, но так и не успели этого сделать, про какое-то просто читали в обзорах подобных тому, что читаете вы.

В итоге, как нам кажется у нас получился самый полный список программного обеспечения для систем видеонаблюдения.

Все программное обеспечение разбито на три группы:

  • Программное с открытым исходным кодом
  • Бесплатное программное обеспечение с ограниченным функционалом
  • Программное обеспечение бесплатное в течении пробного периода

image
Читать дальше →

Как правильно настроить Wi-Fi

Reading time11 min
Views466K


Введение


Думаю, не ошибусь сильно, если у большинства из нас подключение к интернету выглядит следующим образом: есть некоторый довольно скоростной проводной канал до квартиры (сейчас уже и гигабит не редкость), а в квартире его встречает роутер, который раздаёт этот интернет клиентам, выдавая им «чёрный» ip и осуществляя трансляцию адресов.

Довольно часто наблюдается странная ситуация: при скоростном проводе, с роутера раздаётся совсем узенький wifi-канал, не загружающий и половины провода. При этом, хотя формально Wi-Fi, особенно в его ac-версии поддерживает какие-то огромные скорости, при проверке оказывается, что либо Wi-Fi подключается на меньшей скорости, либо подключается, но не выдаёт скорости на практике, либо теряет пакеты, либо всё вместе.

В какой-то момент и я столкнулся с похожей проблемой, и решил настроить свой Wi-Fi по-человечески. На удивление, это заняло примерно в 40 раз дольше, чем я ожидал. Вдобавок, как-то так случилось, что все инструкции по настройке Wi-Fi, которые я находил, сходились к одному из двух видов: в первом предлагали поставить роутер повыше и выпрямить антенну, для чтения второго же мне не хватало честного понимания алгоритмов пространственного мультиплексирования.

Собственно, эта заметка — это попытка заполнить пробел в инструкциях. Я сразу скажу, что задача до конца не решена, несмотря на приличный прогресс, стабильность подключения всё ещё могла бы быть лучше, поэтому я был бы рад услышать комментарии коллег по описанной тематике.
Читать дальше →

STM32 + EmBlocks — мигаем светодиодами

Reading time3 min
Views67K
Как и просили в комментариях к предыдущей статье о EmBlocks, сегодня я покажу от начала и до конца как создать в EmBlocks простой проект для мигания парой светодиодов.
В качестве отладочной платы мы будем использовать кроху на STM32F103C8.
Вот наш стенд:

Подключаем аноды светодиодов к пинам PB5 и PB6, катоды через резсторы в 390 Ом к земле.
Заставим их перемигиваться

FreeRTOS: межпроцессное взаимодействие

Reading time8 min
Views83K

Здравствуйте. В данной статье я постараюсь описать метод межпроцессного обмена данными и синхронизацию с эвентами.
Ссылки на остальные части:
FreeRTOS: введение.
FreeRTOS: мьютексы и критические секции.
Читать дальше →

Исследование защищенности карты Тройка

Reading time18 min
Views204K
Карта тройка

Карта Тройка представляет из себя универсальный пополняемый электронный кошелек, широко используемый в системах оплаты общественного транспорта Москвы с 2013 года.

Цель данного исследования — выяснить защищенность системы электронного кошелька от подделки баланса, оценить безопасность инфраструктуры, работающей с картой. Вся работа была выполнена без использования специальных технических средств. Использовался дешевый смартфон на платформе Android и персональный компьютер. Общее время, затраченное на исследование, составило 15 дней.

В ходе работы был успешно проведен реверс­-инжиниринг мобильного приложения «Мой проездной», что позволило получить доступ к памяти карты и изучить структуру хранения данных. Были найдены уязвимости, позволяющие выполнить подделку баланса, записанного на электронном кошельке карты Тройка. В результате чего стало возможным использование систем, поддерживающих карту, без оплаты.

Итогом исследования стала разработка приложения TroikaDumper, позволяющего эксплуатировать уязвимости системы электронного кошелька.

Внимание! Данные материалы представлены исключительно в ознакомительных целях. Подделка проездных билетов является уголовным преступлением и преследуется по закону.

Читать дальше →

Эмодзи?! Нет, не слышал

Reading time5 min
Views37K
image В нашу жизнь уже давно вошли эмодзи. И в социальных сетях, и во всевозможных мессенджерах мы используем их не задумываясь, выражая свои эмоции всего одним символом. Но для кроссплатформенного приложения отправка и отображение эмодзи — непростая задача. Проблема заключается в том, что отправленные эмодзи с мобильных приложений не всегда отображаются корректно на веб-сайтах.

Последние версии iOS и Android имеют поддержку более 1200 символов эмодзи, но «десктопный» рынок не может похвастаться такими успехами. Мы же в Badoo хотим и делаем все, чтобы пользователям было комфортно общаться на всех платформах, не имея никаких ограничений в переписке.
Далее я расскажу, каким способом мы добились 100% поддержки эмодзи для веба.
Читать дальше →

Основы Elasticsearch

Reading time12 min
Views709K

Elasticsearch — поисковый движок с json rest api, использующий Lucene и написанный на Java. Описание всех преимуществ этого движка доступно на официальном сайте. Далее по тексту будем называть Elasticsearch как ES.


Подобные движки используются при сложном поиске по базе документов. Например, поиск с учетом морфологии языка или поиск по geo координатам.


В этой статье я расскажу про основы ES на примере индексации постов блога. Покажу как фильтровать, сортировать и искать документы.

Читать дальше →

Отправляем сообщения в Telegram из C#

Reading time2 min
Views98K
TLSharp rocks!

С# — развитый язык с большим количеством библиотек, но среди них нет ни одной работающей реализации Telegram API. Эту ситуацию я хочу исправить с помощью своей небольшой библиотеки TLSharp. В статье будет много кода и один котик.
Читать дальше →

Разбираемся с синтаксисом шаблонов в Angular2

Reading time8 min
Views60K

Многие впервые увидев синтаксис шаблонов Angular2 начинают причитать, мол ужас какой сделали, неужто нельзя было как в Angular1 хотя-бы. Зачем нужно было вводить это разнообразие скобочек, звездочек и прочей ерунды! Однако при ближайшем рассмотрении все становится куда проще, главное не пугаться.

Так как шаблоны в AngularJS являются неотъемлемой его частью, важно разобраться с ними в самом начале знакомства с новой версии этого фреймворка. Заодно обсудим, какие преимущества дает нам данный синтаксис по сравнению с angular 1.x. Причем лучше всего будет рассматривать это на небольших примерах.

Данная статья во многом основана на материалах этих двух статей:



Для того, что бы упростить подачу материала, давайте разберемся. Под AngularJS я буду подразумевать всю ветку Angular 1.x, в то время как под Angular2 — ветку 2.x.

Так же спасибо господину Bronx за ценное дополнение, которое я включил в текст статьи.

Примечание: вечер выходного дня, потому о опечатках и т.д. сообщайте в личку. Премного благодарен и приятного чтения.
Читать дальше →

Новый алгоритм для проверки надёжности паролей

Reading time2 min
Views29K
Многие сайты пытаются помочь пользователям установить более сложные пароли. Для этого устанавливают базовые правила, которые требуют обычно указать хотя бы одну прописную букву, одну строчную букву, одну цифру и так далее. Правила обычно примитивные вроде таких:

'password' => [
    'required',
    'confirmed',
    'min:8',
    'regex:/^(?=\S*[a-z])(?=\S*[A-Z])(?=\S*[\d])\S*$/',
];

К сожалению, такие простые правила означают, что пароль Abcd1234 будет признан хорошим и качественным, так же как и Password1. С другой стороны, пароль mu-icac-of-jaz-doad не пройдёт валидацию.

Некоторые специалисты говорят, что это не лучший вариант.
Читать дальше →

Рисуем на тайлах электронной карты в MSSQL

Reading time37 min
Views10K
Хочу рассказать читателям хабра-сообщества как используя CLR библиотеку Microsoft.SqlServer.Types можно формировать тайлы для электронной карты. В статье пойдёт речь о генерации списка картографических тайлов для их дальнейшего рендеринга. Будет описан алгоритм генерации тайлов по геометрии объектов, хранящейся в базе данных MS SQL 2008. Весь процесс рендеринга шаг за шагом будет рассмотрен на примере в конце статьи.



Содержание




Проблема
Исходные данные
Решение
Хранилище тайлов
Этапы подготовки тайлов
Используемые функции
Пример с ломаной линией
Проверка пересечения
Таблицы для хранения образов тайлов
Размещение иконки на тайле
Объединение тайлов
Отрисовка геометрии на тайле
Заключение
Читать дальше →

«Парадокс инспекции» встречается повсюду

Reading time3 min
Views47K
Многим известен так называемый «парадокс дружбы» (friendship paradox) в социальных сетях, впервые упомянутый в научной работе 1991 года, когда социальные сети были только в офлайне. Этот парадокс применим и к современным социальным сетям в интернете.

Если взять любого пользователя Facebook и случайным образом выбрать любого из его друзей, то с вероятностью 80% у друга будет больше «френдов». Люди, которые плохо знакомы с математической статистикой, очень огорчает тот факт, что почти все френды более «успешны» в общении, чем они сами. Но здесь нет причины для депрессии: так и должно быть, в соответствии с наукой и здравым смыслом.

Парадокс дружбы — одна из форм «парадокса инспекции» (Inspection Paradox), который встречается буквально повсюду и частенько вводит в заблуждение обывателей.
Читать дальше →

Favicons, Touch Icons, Tile Icons и т. д. Что выбрать?

Reading time6 min
Views155K
От переводчика.
Это перевод статьи Филипа Бернарда с сайта css-tricks.com. Часть статьи, содержащую описание работы с созданным им сервисом, я позволил себе опустить. Если вы найдете ошибки, просьба сообщить о них в личном сообщении.

Статья содержит результаты проведенного им исследования, каким должен быть фавикон (и то что его заменяет), чтобы хорошо отображаться в различных случаях.


Фавикон был представлен в 1999 году, в Internet Explorer 5 (источник) и стандартизирован W3C несколько месяцев спустя. Это была маленькая иконка, представляющая сайт.



С тех пор большинство настольных браузеров следуют тенденции и используют фавикон тем или иным способом. Это очень просто, не так ли? Создать маленькую картинку и добавить в любой интернет-проект, чтобы сделать его «завершённым». Ничего сложного.
Или нет?

Расследование одного взлома или как быстро и просто потратить миллиард

Reading time6 min
Views157K
UPDATE: Всем привет! Сегодня с удивлением узнал от коллег об этой записи. Выяснилось, что мой аккаунт взломали — представители Хабрахабра это подтвердили и восстановили мне доступ и сейчас разбираются, как так получилось. Но я оставляю эту запись как есть, для истории.
В комментариях уже отметились представители Яндекса: говорят, что уязвимость закрыта, ведётся аудит безопасности софта.

И, пользуясь случаем, хочу напомнить, что у нас в Badoo уже несколько лет идет программа "Проверь Badoo на прочность" и мы платим за найденные уязвимости.


Все вокруг постоянно рассуждают о коррупции. А я хочу рассказать Вам о случае, на коррупцию очень похожем, но в среде чистого IT-бизнеса, на государство никак не завязанного.

Описываемый далее случай интересен именно с точки зрения взлома бизнеса, хотя статья больше посвящена взлому в смысле IT.

Начну с нетехнической части.
Читать дальше →

Information

Rating
Does not participate
Location
Москва, Москва и Московская обл., Россия
Date of birth
Registered
Activity