NSUKit 1.4.0
板卡级统一交互接口
载入中...
搜索中...
未找到
stream_awg.cpp
浏览该文件的文档.
1
2// Copyright (c) 2024. Naishu
3// NSUKit is licensed under Mulan PSL v2.
4// You can use this software according to the terms and conditions of the Mulan PSL v2.
5// You may obtain a copy of Mulan PSL v2 at:
6// http://license.coscl.org.cn/MulanPSL2
7// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
8// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
9// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
10// See the Mulan PSL v2 for more details.
12
13//
14// Created by jilianyi<jilianyi@naishu.tech> on 2024/5/24.
15//
16
17//
18// Created by ljz_w on 2024/5/22.
19//
20
21/*
22 * +-----------------+ +-------------------+
23 * | | +---------------+ | |
24 * | |-----> | full_queue |---- ptr -->| |
25 * | | +---------------+ | |
26 * | download_thread | | data_generate |
27 * | | +---------------+ | |
28 * | |<----- | empty_queue |<--- ptr ---| |
29 * | | +---------------+ | |
30 * +-----------------+ +-------------------+
31 * @class ThreadSafeQueue
32 */
33
34#include <complex>
35#include <cmath>
36#include <vector>
37#include <iostream>
38#include <numeric>
39
40#include <iostream>
41#include <queue>
42#include <thread>
43#include <condition_variable>
44#include "NSUKit.h"
45
46#define TIME_WIDTH 10e-6
47#define CHANNEL_NUM 6
48#define BLOCK 60000*CHANNEL_NUM*10
49
54template <typename T>
55class ThreadSafeQueue {
56public:
58
59 //
60 void Push(T *value) {
61 std::unique_lock<std::mutex> lock(mutex_);
62 queue_.push(value);
63 lock.unlock();
64 condition_.notify_one();
65 }
66
67 //
68 T *Pop() {
69 std::unique_lock<std::mutex> lock(mutex_);
70 condition_.wait(lock, [this] { return !queue_.empty(); });
71 auto value = (T *)queue_.front();
72 queue_.pop();
73 return value;
74 }
75
76private:
77 std::queue<T *> queue_;
78 std::mutex mutex_;
79 std::condition_variable condition_;
80};
81
82
84
85
86struct Deque {
87 memQueue full{};
89 int stopFlag = 0;
90};
91
92
93//template<typename T>
94//bool generate_signal(float timeWidth, uint32_t freq, uint32_t fs, bool isCos, T* buffer) {
95// uint32_t points = timeWidth * fs * sizeof(T);
96// double step = freq/(double )fs;
97// const uint32_t type_max = ((1 << (sizeof(T) * 8 - 1)) - 1);
98//
99// double signal_alo = isCos?
100// [](float it){return cos(it);} : [](double it){return sin(it);};
101// for(uint32_t i=0; i<points; i++) {
102// buffer[i] = static_cast<T>(signal_alo(2 * M_PI * i * step)*type_max);
103// }
104// return true;
105//}
106
107
117template<typename T>
118bool generate_signal_iq(float timeWidth, uint32_t freq, uint32_t fs, T* buffer) {
119 uint32_t points = timeWidth * fs * sizeof(T)*2;
120 double step = freq/(double )fs;
121 const uint32_t type_max = ((1 << (sizeof(T) * 8 - 1)) - 1);
122
123 for(uint32_t i=0; i<points; i=i+2) {
124 buffer[i] = static_cast<T>(cos(2 * M_PI * i * step)*type_max);
125 buffer[i+1] = static_cast<T>(sin(2 * M_PI * i * step)*type_max);
126 }
127 return true;
128}
129
130
140template<typename T>
141bool generate_signal_iq_reverse(float timeWidth, uint32_t freq, uint32_t fs, T* buffer) {
142 uint32_t points = timeWidth * fs * sizeof(T)*2;
143 double step = freq/(double )fs;
144 const uint32_t type_max = ((1 << (sizeof(T) * 8 - 1)) - 1);
145
146 for(uint32_t i=0; i<points; i=i+2) {
147 buffer[i] = static_cast<T>(sin(2 * M_PI * i * step)*type_max);
148 buffer[i+1] = static_cast<T>(cos(2 * M_PI * i * step)*type_max);
149 }
150 return true;
151}
152
153
163void download_thread(nsukit::BaseKit *_kit, Deque *q, nsuSize_t block, nsuSize_t total, std::mutex *mu, nsuRegAddr_t total_DDR_depth) {
164
165 std::unique_lock<std::mutex> *lock;
166 nsuMemory_p mem;
167 nsuSize_t current = 0;
168 nsuRegAddr_t current_DDR_depth = 0;
169 nsuRegValue_t *buff;
170
171
172 while (true) {
173 mem = q->empty.Pop();
174
175 // 当DDR深度不足6MB时,叫停程序
176// _kit->read(0x00270000 + 0x9004, buff);
177// current_DDR_depth = *buff * 64;
178// while ((total_DDR_depth - current_DDR_depth) < block) {
179// _kit->read(0x00270000 + 0x9004, buff);
180// current_DDR_depth = *buff * 64;
181//
182// // 睡眠 1ms
183// std::this_thread::sleep_for(std::chrono::milliseconds(1));
184// }
185
186 auto s = _kit->open_send(0, mem, block, 0);
188 std::cout << "Establish CS and CR connections: " << std::endl;
189 std::cout << "Failed to enable data uplink " << nsukit::status2_string(s) << ", currently uplinked: " << current << std::endl;
190 break;
191 }
192
193 std::this_thread::sleep_for(std::chrono::milliseconds(10));
194
197 s = _kit->wait_stream(mem, 1.);
198 }
199 current += block;
200 q->full.Push(mem);
201// if (current == total) break;
202 }
203 lock = new std::unique_lock<std::mutex>(*mu);
204 q->stopFlag = 1;
205 delete lock;
206}
207
218void data_generate(nsukit::BaseKit *_kit, Deque *q, nsuSize_t block, std::mutex *mu,
219 uint32_t total_sampling_points, uint32_t sampling_rate, uint32_t signal_frequency) {
220 nsuMemory_p mem;
221 int8_t *buffer;
222 int cnt = 0;
223 nsuSize_t speed_count;
224 auto st = std::chrono::steady_clock::now();
225 unsigned int current;
226 int pack_len = 32;
227
228 uint32_t points = TIME_WIDTH*sampling_rate*2;
229 uint32_t points_align = std::ceil(points/(float)pack_len)*pack_len;
230 auto signal = (int8_t *)malloc(points_align);
231 generate_signal_iq_reverse<int8_t>(TIME_WIDTH, signal_frequency, sampling_rate, signal);
232 uint32_t last_offset = 0;
233
234 std::cout << TIME_WIDTH << " " << sampling_rate << " " << points_align*CHANNEL_NUM << " " << pack_len << std::endl;
235
236 while (true) {
237 {
238 auto lock = std::unique_lock<std::mutex>(*mu);
239 if (q->stopFlag == 1) break;
240 }
241 mem = q->full.Pop();
242 buffer = (int8_t *)_kit->get_buffer(mem, block);
243 current = 0;
244
245 while(current+points_align*CHANNEL_NUM <= block) { // memory iter
246 uint32_t offset;
247 for (offset=last_offset;offset<points_align;offset+=pack_len) {
248 uint32_t mem_offset = current+offset*CHANNEL_NUM;
249 for(int ch=0;ch<CHANNEL_NUM;ch++) {
250 memcpy(buffer+mem_offset+ch*pack_len, signal+offset, pack_len);
251 }
252 }
253// current += points_align * CHANNEL_NUM;
254 current += (points_align-last_offset)*CHANNEL_NUM;
255 last_offset = offset+pack_len;
256 if(last_offset >= points_align) last_offset = 0;
257 }
258 if (current+points_align*CHANNEL_NUM > block) {
259 int _len = block-current;
260 uint32_t offset;
261 for(offset=last_offset;offset<last_offset+_len/CHANNEL_NUM;offset+=pack_len) {
262 uint32_t mem_offset = current+offset;
263 for(int ch=0;ch<CHANNEL_NUM;ch++) {
264 memcpy(buffer+mem_offset+ch*pack_len, signal+offset, pack_len);
265 }
266 last_offset = offset+pack_len;
267 if(last_offset >= points_align) last_offset = 0;
268 }
269 }
270 q->empty.Push(mem);
271 speed_count += block;
272
273 if (cnt % 20 == 0) {
274 auto count = std::chrono::steady_clock::now() - st;
275 std::cout << std::flush << '\r' << "当前数据生成速度: " << speed_count*1000./(count.count()) << "MB/s" << std::endl;
276// speed_count = 0;
277 }
278 }
279 free(signal);
280 std::cout << std::endl;
281}
282
283
284int main(int argc, char *argv[]) {
285 Deque q;
286 std::mutex mu;
287
288 /* 初始化NSUSoc实例,采用PCIE相关协议 */
289 nsukit::NSUSoc <nsukit::PCIECmdUItf, nsukit::PCIECmdUItf, nsukit::PCIEStreamUItf> kit{};
290
291 if (argc != 5) {
292 std::cout << "Unsupported parameter passing method" << std::endl;
293 // ./DataDownloadRreverseStop DDR总深度 总采样点数 采样率 信号频率
294 std::cout << argv[0] << " {DDR total depth} {total sampling points} {sampling rate} {signal frequency}" << std::endl;
295 return 1;
296 }
297
298 nsuRegAddr_t total_DDR_depth = std::atoi(argv[1]); // DDR总深度,单位:B
299
300 /* PCIe协议的初始化参数 */
301 nsuInitParam_t param;
302 param.stream_board = 0;
303
304 int total_sampling_points = std::atoi(argv[2]); // 总采样点数
305 int sampling_rate = std::atoi(argv[3]); // 采样频率
306 int signal_frequency = std::atoi(argv[4]); // 信号频率
307 // 包长与信号时宽的最小公倍数
308 unsigned int ds_block = BLOCK;
309// unsigned int ds_block = std::lcm(
310// CHANNEL_NUM*32,
311// static_cast<int>(sampling_rate*TIME_WIDTH* sizeof(int8_t )*CHANNEL_NUM));
312
313
314 // 根据总采样点数求数据总量
315 int total_len = total_sampling_points * 2;
316
317 /* 查看PCIe的方法 */
318 //auto res = kit.link_cmd(&param);
319 //if (res != nsukitStatus_t::NSUKIT_STATUS_SUCCESS) {
320 // std::cout << "Establish CS and CR connections: " << nsukit::status2_string(res) << std::endl;
321 //}
322 auto res = kit.link_stream(&param);
324 std::cout << "Establish a DS connection: " << nsukit::status2_string(res) << std::endl;
325 }
326
327 // 申请10个6MB的空间
328 for (int i=0; i<10; i++) {
329 nsuMemory_p mem = kit.alloc_buffer(ds_block);
330 q.full.Push(mem);
331 }
332
333 // 通知FPGA开始采集
334 //res = kit.execute("系统开启");
335 //if (res != nsukitStatus_t::NSUKIT_STATUS_SUCCESS) {
336 // std::cout << "系统开启:" << nsukit::status2_string(res) << std::endl;
337 //}
338
339 // 线程
340 // 线程A 开启下行
341 std::thread up_trd(download_thread, &kit, &q, ds_block, total_len, &mu, total_DDR_depth);
342 // 线程B 数据生成
343 std::thread generate_trd(data_generate, &kit, &q, ds_block, &mu, total_sampling_points, sampling_rate, signal_frequency);
344
345 up_trd.join();
346 generate_trd.join();
347
348 // 通知FPGA开始采集
349 //res = kit.execute("系统停止");
350 //if (res != nsukitStatus_t::NSUKIT_STATUS_SUCCESS) {
351 // std::cout << "系统停止:" << nsukit::status2_string(res) << std::endl;
352 //}
353
354 std::cout << "Data download completed" << std::endl;
355
356 return 0;
357}
358
359
void Push(T *value)
Definition: stream_awg.cpp:60
virtual nsuVoidBuf_p get_buffer(nsuMemory_p fd, nsuStreamLen_t length=0)
Definition: base_kit.h:76
virtual nsukitStatus_t open_send(nsuChnlNum_t chnl, nsuMemory_p fd, nsuStreamLen_t length, nsuStreamLen_t offset=0)
Definition: base_kit.h:93
virtual nsukitStatus_t wait_stream(nsuMemory_p fd, float timeout=0.)
Definition: base_kit.h:103
std::string NSU_DLLEXPORT status2_string(nsukitStatus_t status)
Definition: config.cpp:15
bool generate_signal_iq_reverse(float timeWidth, uint32_t freq, uint32_t fs, T *buffer)
Definition: stream_awg.cpp:141
void data_generate(nsukit::BaseKit *_kit, Deque *q, nsuSize_t block, std::mutex *mu, uint32_t total_sampling_points, uint32_t sampling_rate, uint32_t signal_frequency)
Definition: stream_awg.cpp:218
#define BLOCK
Definition: stream_awg.cpp:48
#define CHANNEL_NUM
Definition: stream_awg.cpp:47
#define TIME_WIDTH
Definition: stream_awg.cpp:46
void download_thread(nsukit::BaseKit *_kit, Deque *q, nsuSize_t block, nsuSize_t total, std::mutex *mu, nsuRegAddr_t total_DDR_depth)
Definition: stream_awg.cpp:163
ThreadSafeQueue< void > memQueue
Definition: stream_awg.cpp:83
bool generate_signal_iq(float timeWidth, uint32_t freq, uint32_t fs, T *buffer)
Definition: stream_awg.cpp:118
int stopFlag
memQueue empty
memQueue full
nsuBoardNum_t stream_board
Definition: type.h:121
@ NSUKIT_STATUS_STREAM_RUNNING
DLLEXTERN typedef size_t nsuSize_t
Definition: type.h:87
DLLEXTERN typedef void * nsuMemory_p
Definition: type.h:86
DLLEXTERN typedef uint32_t nsuRegValue_t
Definition: type.h:90
DLLEXTERN typedef uint32_t nsuRegAddr_t
Definition: type.h:89