aboutsummaryrefslogtreecommitdiffstats
path: root/AiS_TX.py
blob: 5ea5deb5b2d3e3f9528a81575591b9e528506430 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#!/usr/bin/env python
#
# This script is part of the AIS BlackToolkit.
# AiS_TX.py implements a software-based AIS transmitter accordingly to specifications (ITU-R M.1371-4).
#
# A fully functional GnuRadio installation is required, including our AIS Frame Builder block, namely gr-aistx.
#
# Tested on:
# GnuRadio 3.6.5.1
# Debian 7.1.0 wheezy
# GNU C++ version 4.7.3; Boost_104900 
# UHD_003.005.003-0-unknown
# Ettus USRP B100 Version 2)
# 
# Copyright 2013-2014 -- Embyte & Pastus
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# Usage example: 
# $ ./AIVDM_Encoder.py --type=1 --mmsi=970010000 --lat=45.6910 --long=9.7235 | xargs -IX ./AiS_TX.py --payload=X --channel=A
#

from gnuradio import blocks
from gnuradio import digital
from gnuradio import eng_notation
from gnuradio import gr
from gnuradio import uhd
from gnuradio.eng_option import eng_option
from gnuradio.gr import firdes
from grc_gnuradio import wxgui as grc_wxgui
from optparse import OptionParser
import AISTX
import time
import wx

class top_block(grc_wxgui.top_block_gui):

	def __init__(self, p, c, pw, ff, sr, br):
		grc_wxgui.top_block_gui.__init__(self, title="Top Block")
		_icon_path = "/usr/share/icons/hicolor/32x32/apps/gnuradio-grc.png"
		self.SetIcon(wx.Icon(_icon_path, wx.BITMAP_TYPE_ANY))

		##################################################
		# Variables
		##################################################
		self.samp_rate = samp_rate = sr
		self.channel_select = channel_select = c
		self.bit_rate = bit_rate = br

		##################################################
		# Blocks
		##################################################
		self.uhd_usrp_sink_0 = uhd.usrp_sink(
			device_addr="",
			stream_args=uhd.stream_args(
				cpu_format="fc32",
				channels=range(1),
			),
		)
		self.uhd_usrp_sink_0.set_samp_rate(samp_rate)
		self.uhd_usrp_sink_0.set_center_freq(uhd.tune_request_t(161975000+50000*c,ff), 0)
		self.uhd_usrp_sink_0.set_gain(-10, 0)
		self.uhd_usrp_sink_0.set_antenna("TX/RX", 0)
		self.digital_gmsk_mod_0 = digital.gmsk_mod(
			samples_per_symbol=int(samp_rate/bit_rate),
			bt=0.4,
			verbose=False,
			log=False,
		)
		self.blocks_multiply_const_vxx_0 = blocks.multiply_const_vcc((0.9, ))
		self.AISTX_Build_Frame_0 = AISTX.Build_Frame(p, False, True)

		##################################################
		# Connections
		##################################################
		self.connect((self.AISTX_Build_Frame_0, 0), (self.digital_gmsk_mod_0, 0))
		self.connect((self.digital_gmsk_mod_0, 0), (self.blocks_multiply_const_vxx_0, 0))
		self.connect((self.blocks_multiply_const_vxx_0, 0), (self.uhd_usrp_sink_0, 0))


	def get_samp_rate(self):
		return self.samp_rate

	def set_samp_rate(self, samp_rate):
		self.samp_rate = samp_rate
		self.uhd_usrp_sink_0.set_samp_rate(self.samp_rate)

	def get_channel_select(self):
		return self.channel_select

	def set_channel_select(self, channel_select):
		self.channel_select = channel_select
		self.analog_sig_source_x_0.set_frequency(-25000+50000*self.channel_select)

	def get_bit_rate(self):
		return self.bit_rate

	def set_bit_rate(self, bit_rate):
		self.bit_rate = bit_rate

if __name__ == '__main__':

	desc="""GnuRadio-Based AIS Transmitter. Copyright Embyte & Pastus 2013-2014."""

	parser = OptionParser(option_class=eng_option, usage="%prog: [options]", description=desc)
	
	parser.add_option("--payload", help="""Specify the message payload to transmit 
	                                    (e.g., crafted via AIVDM_Encoder)""")
	parser.add_option("--channel", help="""Specify the AIS channel:
	                                    - A: 161.975Mhz (87B)
	                                    - B: 162.025Mhz (88B)""")
	parser.add_option("--power", help="""Specify the transmisson power, between -12dB and +12dB (default is -10dB)""", type="int", default = -10)
	parser.add_option("--filter_frequency", help="""Specify the filter frequency (default is 19MHz)""", type="int", default = 19000000)
	parser.add_option("--sampling_rate", help="""Specify the sampling rate (default is 326.531KHz)""", type="int", default = 326531)
	parser.add_option("--bit_rate", help="""Specify the bit rate (default is 9600 baud)""", type="int", default = 9600)	
	
	(options, args) = parser.parse_args()
	
	if not options.payload:
		parser.error("Payload not specified: -h for help.")

	if not options.channel:
		parser.error("Channel not specified: -h for help.")
		
	if options.channel!="A" and options.channel!="B":
		parser.error("Channel accepts value A or B: -h for help")
	    
	channel_ID = 0 if options.channel=="A" else 1

	tb = top_block(p=options.payload, c=channel_ID, pw=options.power, ff=options.filter_frequency, sr=options.sampling_rate, br=options.bit_rate)
	tb.Run(True)