In the previous article, we built the minimal working example walking a parse tree using a listener. In this article, we are going to store a parsed CSV structure into a variable to use in the future.
use antlr_rust::common_token_stream::CommonTokenStream; use antlr_rust::input_stream::InputStream; use antlr_rust::parser_rule_context::ParserRuleContext; use antlr_rust::tree::{ErrorNode, ParseTreeListener, TerminalNode};
Import grammar-specific things:
1 2 3 4 5 6
mod csvlexer; mod csvlistener; mod csvparser; use csvlexer::CSVLexer; use csvlistener::CSVListener; use csvparser::*;
Implement ParseTreeListener, a supertraint of CSVListener:
True range multilateration is a method to determine the location of a movable vehicle or stationary point in space using multiple ranges (distances) between the vehicle/point and multiple spatially-separated known locations (often termed ‘stations’). — True range multilateration, Wikipedia
We can define a trilateration as an optimization problem to minimize a cost function \(S\) for a given estimate \(\beta\), a tuple of \((x, y, z)\)
For example, it’s tricky to validate a commit with pre-commit hook if an app does not return a proper exit code. Here’s a way to validate with the stderr.
Although Amazon provides great documentation, this is what all I needed to send an email with Amazon SES (Simple Email Service) on Node.js.
Get Started with Amazon SES
To start, visit Amazon SES and hit Get started with Amazon SES. Then Amazon asks which region you want to use SES. Note that region for SES doesn’t need to be the same with your other Amazon services.
Verify Your Domain or Email Address
After choosing the region, you will see the page above. I highlighted menus you need. You can use two types of identities, domains and email addresses. If you have your own domain and you want to send an email from the domain, the first one needs to be configured. If you want to send an email from your existing email account such as Gmail and Outlook, the second one needs to be configured. The first one and the second one is not mutually exclusive. You can use both.
Option 1: Verify Your Domain
After entering Domains menu, hit Verify a New Domain.
In the popup, type your domain in interest, check Generate DKIM Settings and hit Verify This Domain.
For a given domain, SES requests you to configure DNS records in order to verify whether the domain is owned by you. SES will try to verify the domain constantly. If verification succeeds, you will see Verification: verified, DKIM Status: verified, Enalbed for: Yes in the dashboard as shows in the above. Then it’s all set.
Option 2: Verify Your Email Address
Verifying an email address is simpler. After entereing Email Addresses menu, hit Verify a New Email Address and type an email address in interest. And then SES will send a verification email to a given email address. Once you visit a link given in the verification email, the email address will be verified. Then it’s all set.
Build Node.js Application Sending Email with SES
Install AWS SDK
1
$ npm install aws-sdk
Configure AWS Credentials
To verify whether your Node.js application has the right permissions to send an email with SES, you need to provide the right credentials to AWS SDK.
The simplest Node.js script sending an email with SES is provided in Amazon Documentation or its GitHub repository, so I’ll skip the entire script here:
Initially, your SES operates in sandbox mode andcan send an email only to domains or email addresses which you verified in the above. To be able to send an email to anyone, you need to Request a Sending Limit Increase.
Visit Create Case and create a case to request a sending limit increase.
DW1000 is a UWB communication and ranging module manufactured by DecaWave. It provides a fairly good ranging accuracy (< 2 cm). Not only a simple anchor-tag ranging system, let’s make a practical centimeter-level precision indoor positioning system using it
System Design
Overview
A setup is shown in a figure below:
A tag
A tag is composed of two components—Raspberry Pi and Arduino Pro Mini
Raspberry Pi controles a higher level indoor positioning system
It triggers Arduino Pro Mini to probe anchors and measure distance between it and each anchor
It requests distance measurements on Arduino Pro Mini and locate itself through trilateration
Arduino Pro Mini
It is required due to similar reasons of anchors
It receives commands from Raspberry Pi and executes the corresponding process Processes are:
Probing anchors nearby and exchanging series of frames with each anchor to measure distance
Reporting probed anchors and measured distance values
Anchors
They are deployed in a site of interest and their 2D/3D coordinates are known
They are implemented on Arduino Pro Mini for the following reasons:
Arduino Pro Mini’s low power consumption
Anchor’s fast response requirement (order of milliseconds)
Anchor’s simple tasks (receiving and transmitting UWB frames)
An overall sequence diagram is illustrated below. Tag (Arduino) is actually composed of Arduino Pro Mini and DW1000.
State Machine: Tag
A figure below is a state diagram of a tag:
When a Raspberry Pi commands via I2C to scan, it goes into SCAN state and broadcasts a PING message. Going into PONG state immediately, it waits for PONG messages from anchors nearby for a certain duration. I set it to 100 ms.
If it discovers 3 or more anchors during the PONG state, it goes into ROUNDROBIN state. It exchanges 4 messages with each discovered anchor sequentially, i.e. POLL to an anchor, POLL_ACK from an anchor, RANGE to an anchor, and RANGE_REPORT from an anchor. After sending POLL and RANGE message, it waits for a response message for a certain timeout of 10 ms.
After 4 messages are exchanged with each anchor, it calculates distance between an anchor using Tx/Rx timestamp. It adopts two-way ranging algorithm, which is a bit computational intensive, but I think it is not that much intensive. For more information about two-way ranging, please refer the official appliclation note APS013 by DecaWave.
State Machine: Anchor
A state diagram of an anchor is simple:
It normally stays at IDLE state
If it receives a PING message, it tries to send a PONG message with a random delay between 0 and 90 ms to avoid the collision and goes into PENDING_PONG state
If it receives a POLL message and sends a POLL_ACK message, it goes into RANGE state and waits for a RANGE message is received
If timeout of 10 ms expires, it returns to IDLE state
If it receives a RANGE message, it sends a RANGE_REPORT message to a tag
Implementation
The whole implementation can be found in my GitHub repository. I used arduino-dw1000 for controlling DW1000 using Arduino. I followed wiring between Arduino Pro Mini and DW1000 as defined in examples/Ranging{Anchor,Tag} of the library. Only I2C interface is needed to connect Raspberry Pi and Arduino Pro Mini
Contrast to Linux and macOSs, many are having difficult times building and using Thrift on Windows 10. Most Thrift guides on the internet miss some parts. Here’s the correct way to build and use Thrift on Windows 10.
Dependencies
Boost
OpenSSL (for secure socket)
libevent (for callback)
Boost
Download boost. At this time of writing, the latest version is 1.64.0. I downloaded boost_1_64_0-msvc-14.1-64.exe.
You must download a correct binary with consideration of OS addressing mode (32/64 bits) and MSVC version
You can check MSVC version in a project property page of a project which will use Thrift
Execute the downloaded file to extract files. In my case, C:\boost_1_64_0
Open **Native Tools Command Prompt** and execute the following commands
EVK1000 and TREK1000 are Two-way Ranging Evaluation Kit for DecaWave’s UWB DW1000 chip. You can see and evaluate a ranging result on a screen of each of them. However, to see a positioning result, you need to connect one of them with a PC and use DecaWave’s dedicated software only on Windows. Here’s how to read data from EVK1000 without the dedicated software
Preparing a Driver
This kit has a COM (serial) port. But this port is wrapped with USB interface and operates with a virtual COM port driver
On Windows, a driver for this (STM32 Virtual ComPort in FS Mode v1.4.0) can be downloaded at here. After downloading and extracting the file, run <OS>/dpinst_<arch>.exe where <OS> and <arch> are your OS and architecture, respectively. A related thread can be found here
On Linux and macOS, when a board is connected, a driver will be automatically loaded
Configure anchors and a tag by flipping switches as instruction says, and connect an anchor or a tag with a PC. Since it uses a virtual COM port, serial communication parameters are automatically configured and you don’t need to worry about it
When connection is successful, you can see outputs on a serial port terminal as the following:
Wi-Fi regulation defines various restirctions such as transmission power, initial radiation, and dynamic frequency switching for Wi-Fi to operate in a certain country. Most OSs including Linux contain regulations in their kernels, and we can bypass them by modifying a regulation file or a kernel.
However, certain Wi-Fi cards such as Intel’s have their own regulations in their EEPROM, which takes precedence to kernel’s regulations. Here’s how to modify regulations in Intel Wi-Fi card’s EEPROM. In this article, Intel Ultimate N WiFi Link 5300 is used
Preparing a Tool
iwleeprom is a software to read and write content in an EEPROM. Clone, build and install it:
1 2 3 4
$ git clone [https://github.com/0x90/iwleeprom](https://github.com/0x90/iwleeprom) $ cd iwleeprom $ make $ [sudo] make install
Interpreting a Regulation Flag
First, let’s have a look at what EEPROM contains. To read regulations in EEPROM, type iwleeprom -s:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
$ iwleeprom -s Supported devices detected: [1] 0000:03:00.0 [RW] Ultimate N WiFi Link 5300 (8086:4236, 8086:1011) Select device [1-1] (or 0 to quit): 1 Using device 0000:03:00.0 [RW] Ultimate N WiFi Link 5300 No file names given or patch option selected! No EEPROM actions will be performed, just write-enable test Regulatory data from card EEPROM... Regulatory base: 0156 Channel 1: 0e6f Channel 2: 0f6f ... Channel 64: 0f31 ... Channel 1 (HT40): 0a6f Channel 2 (HT40): 0f6f ... Channel 157 (HT40): 0f61
What those 0e6f, 0f31 and other things mean? Those are flags defining regulations. So, which bit stands for what? When you are looking into Linux kernel source code, specifically, iwlwifi driver, you can see flag definition as below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/** * enum iwl_eeprom_channel_flags - channel flags in EEPROM * @EEPROM_CHANNEL_VALID: channel is usable for this SKU/geo * @EEPROM_CHANNEL_IBSS: usable as an IBSS channel * @EEPROM_CHANNEL_ACTIVE: active scanning allowed * @EEPROM_CHANNEL_RADAR: radar detection required * @EEPROM_CHANNEL_WIDE: 20 MHz channel okay (?) * @EEPROM_CHANNEL_DFS: dynamic freq selection candidate */ enumiwl_eeprom_channel_flags { EEPROM_CHANNEL_VALID = BIT(0), EEPROM_CHANNEL_IBSS = BIT(1), EEPROM_CHANNEL_ACTIVE = BIT(3), EEPROM_CHANNEL_RADAR = BIT(4), EEPROM_CHANNEL_WIDE = BIT(5), EEPROM_CHANNEL_DFS = BIT(7), };
For example, channel 1 has flags 0e6f, which is 1110 0110 1111 in binary. Its interpretation is:
1 2 3 4 5 6 7 8
1110 0110 1111 .............1 This channel is valid ............1. Not valid for IBSS ...........1.. (Unknown) ..........1... Active scanning is allowed ........0..... RADAR detection is not required .......1...... Supports wide band ......1....... Candidate for dynamic frequency selection
Reading EEPROM
To read and dump EEPROM, type iwleeprom -o <outfile>:
1 2 3 4 5 6 7 8 9 10 11 12
$ iwleeprom -b -o eeprom_dump Supported devices detected: [1] 0000:03:00.0 [RW] Ultimate N WiFi Link 5300 (8086:4236, 8086:1011) Select device [1-1] (or 0 to quit): 1 Using device 0000:03:00.0 [RW] Ultimate N WiFi Link 5300 Saving dump with byte order: BIG ENDIAN 0000 [................................................................] 0080 [................................................................] ... 0780 [................................................................]
EEPROM has been dumped to eeprom_dump
We can view the dumped EEPROM with xxd command or hex mode (:%!xxd) in vim, and can find channel flags. They are written in the same order of channels, but their offsets are not in linear relationships. You can manually locate an offset of each channel:
It is easy. Open the dumped EEPROM in vim and set to hex mode (:%!xxd). And change the content as you want. To save changes, reert hex mode (:%!xxd -r) and save it (:w)
Writing New Regulations in EEPROM
After finishing modification, rewrite EEPROM with iwleeprom -m -c -i <infile>:
1 2 3 4 5 6 7 8 9 10 11 12
$ iwleeprom -m -c -i eeprom_dump Supported devices detected: [1] 0000:03:00.0 [RW] Ultimate N WiFi Link 5300 (8086:4236, 8086:1011) Select device [1-1] (or 0 to quit): 1 Using device 0000:03:00.0 [RW] Ultimate N WiFi Link 5300 Dump file byte order: BIG ENDIAN 0000 [================================================================] 0080 [================================================================] ... 0780 [================================================================]
EEPROM has been written from eeprom_dump
Finally, you can check modification is applied via iw phy command