blob: 16662988f60ec9621b64ea7538043796d9ec3ce2 [file] [log] [blame]
Brian Silverman8efe23e2013-07-07 23:31:37 -07001begin
2 require "sha1"
3rescue LoadError
4 require "digest/sha1"
5end
6
Parker Schuh711db3e2014-02-12 09:47:34 -08007class Target::StructBase < Target::Node
8 def create_DoGetType(type_class, cpp_tree)
Brian Silverman665e60c2014-02-12 13:57:10 -08009 member_func = CPP::MemberFunc.new(type_class,"const ::aos::MessageType*","DoGetType")
Parker Schuh711db3e2014-02-12 09:47:34 -080010 member_func.static = true
Parker Schuh711db3e2014-02-12 09:47:34 -080011 fields = []
Brian Silverman665e60c2014-02-12 13:57:10 -080012 register_members = []
Parker Schuh711db3e2014-02-12 09:47:34 -080013 @members.each do |member|
14 tId = member.getTypeID()
15 fieldName = member.name.inspect
16 if(member.respond_to?(:add_TypeRegister))
Brian Silverman665e60c2014-02-12 13:57:10 -080017 register_members.push(member)
Parker Schuh711db3e2014-02-12 09:47:34 -080018 end
19 fields << "new ::aos::MessageType::Field{#{tId}, #{fieldName}}"
20 end
Brian Silverman665e60c2014-02-12 13:57:10 -080021 register_members.uniq do |member|
22 member.type
23 end.each do |member|
24 member.add_TypeRegister(cpp_tree, type_class, member_func)
25 end
Parker Schuh711db3e2014-02-12 09:47:34 -080026 id = getTypeID()
Brian Silverman16c82972014-02-13 15:36:40 -080027 member_func.suite << ("static const ::aos::MessageType kMsgMessageType(#{type_class.parent_class ? type_class.parent_class + '::Size()' : 0}, #{id}, #{@loc.queue_name(@name).inspect}, {" +
Parker Schuh711db3e2014-02-12 09:47:34 -080028 "#{fields.join(", ")}})");
29 type_class.add_member(member_func)
Brian Silverman665e60c2014-02-12 13:57:10 -080030 member_func.suite << "::aos::type_cache::Add(kMsgMessageType)"
Parker Schuh711db3e2014-02-12 09:47:34 -080031 member_func.suite << CPP::Return.new("&kMsgMessageType")
32 end
Brian Silverman16c82972014-02-13 15:36:40 -080033 def create_InOrderConstructor(type_class, cpp_tree)
34 cons = CPP::Constructor.new(type_class)
35 type_class.add_member(cons)
36 @members.each do |member|
37 if member.respond_to?(:type_name)
38 type_name = member.type_name(cpp_tree)
39 else
40 type_name = member.type
41 end
42
43 cons.args << "#{type_name} #{member.name}_in"
44 cons.add_cons(member.name, member.name + '_in')
45 end
46 end
47 def create_DefaultConstructor(type_class, cpp_tree)
48 cons = CPP::Constructor.new(type_class)
49 type_class.add_member(cons)
50 cons.add_cons(type_class.parent_class) if type_class.parent_class
51 cons.suite << CPP::FuncCall.build('Zero')
52 end
53 def create_Zero(type_class,cpp_tree)
54 member_func = CPP::MemberFunc.new(type_class,"void","Zero")
55 type_class.add_member(member_func)
56 @members.each do |elem|
57 elem.zeroCall(member_func.suite)
58 end
59 member_func.suite << CPP::FuncCall.new(type_class.parent_class + '::Zero') if type_class.parent_class
60 end
61 def create_Size(type_class,cpp_tree)
62 member_func = CPP::MemberFunc.new(type_class,"size_t","Size")
63 member_func.inline = true
64 member_func.static = true
65 type_class.add_member(member_func.forward_dec)
66 size = 0
67 @members.each do |elem|
68 size += elem.size
69 end
70 if type_class.parent_class
71 member_func.suite << CPP::Return.new(CPP::Add.new(size,
72 "#{type_class.parent_class}::Size()"))
73 else
74 member_func.suite << CPP::Return.new(size)
75 end
76 end
77 def create_Serialize(type_class,cpp_tree)
78 member_func = CPP::MemberFunc.new(type_class,"size_t","Serialize")
79 type_class.add_member(member_func)
80 member_func.args << "char *buffer"
81 member_func.suite << "#{type_class.parent_class}::Serialize(buffer)" if type_class.parent_class
82 member_func.const = true
83 offset = type_class.parent_class ? type_class.parent_class + '::Size()' : '0'
84 @members.each do |elem|
85 elem.toNetwork(offset,member_func.suite)
86 offset += " + #{elem.size}";
87 end
88 member_func.suite << CPP::Return.new(CPP::FuncCall.new('Size'))
89 end
90 def create_Deserialize(type_class,cpp_tree)
91 member_func = CPP::MemberFunc.new(type_class,"size_t","Deserialize")
92 type_class.add_member(member_func)
93 member_func.args << "const char *buffer"
94 member_func.suite << "#{type_class.parent_class}::Deserialize(buffer)" if type_class.parent_class
95 offset = type_class.parent_class ? type_class.parent_class + '::Size()' : '0'
96 @members.each do |elem|
97 elem.toHost(offset,member_func.suite)
98 offset += " + #{elem.size}";
99 end
100 member_func.suite << CPP::Return.new(CPP::FuncCall.new('Size'))
101 end
Parker Schuh711db3e2014-02-12 09:47:34 -0800102 def simpleStr()
103 return "{\n" + @members.collect() { |elem| elem.simpleStr() + "\n"}.join("") + "}"
104 end
105 def getTypeID()
Brian Silverman1885bd02014-02-13 12:28:12 -0800106 return "0x" + (((Digest::SHA1.hexdigest(simpleStr())[0..3].to_i(16)) << 16) | size).to_s(16)
Parker Schuh711db3e2014-02-12 09:47:34 -0800107 end
108 def add_member(member)
109 @members << member
110 end
111 def size()
112 return @size if(@size)
113 @size = 0
114 @members.each do |elem|
115 @size += elem.size
116 end
117 return @size
118 end
119end
120
121class Target::MessageDec < Target::StructBase
brians343bc112013-02-10 01:53:46 +0000122 attr_accessor :name,:loc,:parent,:msg_hash
123 def initialize(name)
124 @name = name
125 @members = []
126 end
127 def extern=(value)
128 @extern=value
129 end
130 def get_name()
131 if(@parent)
132 return "#{@parent.get_name}.#{@name}"
133 else
134 return "#{@name}"
135 end
136 end
brians343bc112013-02-10 01:53:46 +0000137 def create_Print(type_class,cpp_tree)
138 member_func = CPP::MemberFunc.new(type_class,"size_t","Print")
139 type_class.add_member(member_func)
140 member_func.args << "char *buffer"
141 member_func.args << "size_t length"
142 member_func.const = true
143 format = "\""
144 args = []
145 @members.each do |elem|
146 format += ", "
147 format += elem.toPrintFormat()
Parker Schuh343481e2014-02-09 18:28:43 -0800148 elem.fetchPrintArgs(args)
brians343bc112013-02-10 01:53:46 +0000149 end
Parker Schuh343481e2014-02-09 18:28:43 -0800150 format += "\""
151 member_func.suite << "size_t super_size = ::aos::Message::Print(buffer, length)"
152 member_func.suite << "buffer += super_size"
153 member_func.suite << "length -= super_size"
154 member_func.suite << "return super_size + snprintf(buffer, length, " + ([format] + args).join(", ") + ")";
brians343bc112013-02-10 01:53:46 +0000155 end
Parker Schuh711db3e2014-02-12 09:47:34 -0800156 def create_GetType(type_class, cpp_tree)
Brian Silverman665e60c2014-02-12 13:57:10 -0800157 member_func = CPP::MemberFunc.new(type_class,"const ::aos::MessageType*","GetType")
158 type_class.add_member(member_func)
159 member_func.static = true
Parker Schuh711db3e2014-02-12 09:47:34 -0800160 member_func.suite << "static ::aos::Once<const ::aos::MessageType> getter(#{type_class.name}::DoGetType)"
Brian Silverman665e60c2014-02-12 13:57:10 -0800161 member_func.suite << CPP::Return.new("getter.Get()")
Parker Schuh711db3e2014-02-12 09:47:34 -0800162 end
brians343bc112013-02-10 01:53:46 +0000163 def self.builder_loc(loc)
164 return @builder_loc if(@builder_loc)
165 return @builder_loc = loc.root.get_make("aos")
166 end
167 def type_name(builder_loc,name)
168 if(builder_loc == @loc) #use relative name
169 return name
170 else #use full name
171 return @loc.to_cpp_id(name)
172 end
173 end
174 def create(cpp_tree)
175 return self if(@extern)
176 orig_namespace = namespace = cpp_tree.get(@loc)
177 name = ""
178 if(namespace.class < Types::Type) #is nested
179 name = namespace.name + "_" + name
180 namespace = namespace.space
181 end
182 type_class = namespace.add_struct(name + @name)
183 if(name.length > 0)
184 orig_namespace.add_member(:public, Types::TypeDef.new(type_class,@name))
185 end
186 cpp_tree.set(self,type_class)
187 type_class.set_parent("public ::aos::Message")
Parker Schuh711db3e2014-02-12 09:47:34 -0800188 ts = self.simpleStr()
Brian Silverman8efe23e2013-07-07 23:31:37 -0700189 self.msg_hash = "0x#{Digest::SHA1.hexdigest(ts)[-8..-1]}"
brians343bc112013-02-10 01:53:46 +0000190 type_class.add_member("enum {kQueueLength = 1234, kHash = #{self.msg_hash}}")
191 @members.each do |elem|
192 type_class.add_member(elem.create_usage(cpp_tree))
193 end
194
195 create_Serialize(type_class,cpp_tree)
196 create_Deserialize(type_class,cpp_tree)
197 create_Zero(type_class,cpp_tree)
198 create_Size(type_class,cpp_tree)
199 create_Print(type_class,cpp_tree)
Parker Schuh711db3e2014-02-12 09:47:34 -0800200 create_GetType(type_class, cpp_tree)
201 create_DoGetType(type_class, cpp_tree)
Brian Silverman16c82972014-02-13 15:36:40 -0800202 create_DefaultConstructor(type_class, cpp_tree)
203 create_InOrderConstructor(type_class, cpp_tree)
brians343bc112013-02-10 01:53:46 +0000204
205 b_namespace = cpp_tree.get(b_loc = self.class.builder_loc(@loc))
206
207 safetemplate = Types::TemplateClass.new(b_namespace,"SafeMessageBuilder")
208 ifdef_statement = Types::PreprocessorIf.new(b_namespace,"!defined(__VXWORKS__) && !defined(__TEST_VXWORKS__)")
209 ifdef_statement.add_member(safetemplate)
210 b_namespace.add(ifdef_statement)
211 template = b_namespace.add_template("MessageBuilder")
212 safetemplate.spec_args << t = @loc.to_cpp_id(@name)
213 template.spec_args << t = @loc.to_cpp_id(@name)
214 safemsg_ptr_t = "SafeScopedMessagePtr< #{t}>"
215 msg_ptr_t = "ScopedMessagePtr< #{t}>"
216 safemsg_bld_t = "SafeMessageBuilder< #{t}>"
217 msg_bld_t = "MessageBuilder< #{t}>"
218 safetemplate.add_member(:private,"#{safemsg_ptr_t} msg_ptr_")
219 template.add_member(:private,"#{msg_ptr_t} msg_ptr_")
brians343bc112013-02-10 01:53:46 +0000220 template.add_member(:private,"#{msg_bld_t}(const #{msg_bld_t}&)")
221 template.add_member(:private,"void operator=(const #{msg_bld_t}&)")
222 safetemplate.add_member(:private,"friend class ::aos::Queue< #{t}>")
223 template.add_member(:private,"friend class ::aos::Queue< #{t}>")
224
225 cons = CPP::Constructor.new(template)
226 unsafe_cons = CPP::Constructor.new(template)
227 cons_ifdef_statement = CPP::PreprocessorIf.new(cons, unsafe_cons)
228 cons_ifdef_statement.name = "!defined(__VXWORKS__) && !defined(__TEST_VXWORKS__)"
229 template.add_member(:private,cons_ifdef_statement)
Brian Silverman08661c72013-09-01 17:24:38 -0700230 cons.args << "RawQueue *queue"
brians343bc112013-02-10 01:53:46 +0000231 cons.args << "#{t} *msg"
232 unsafe_cons.args << "#{t} *msg"
233 cons.add_cons("msg_ptr_","queue","msg")
234 unsafe_cons.add_cons("msg_ptr_","msg")
235 cons = safetemplate.add_member(:private,CPP::Constructor.new(safetemplate))
Brian Silverman08661c72013-09-01 17:24:38 -0700236 cons.args << "RawQueue *queue"
brians343bc112013-02-10 01:53:46 +0000237 cons.add_cons("msg_ptr_","queue")
238 safetemplate.public
239 template.public
240 DefineMembers(cpp_tree, safetemplate, safemsg_bld_t)
241 DefineMembers(cpp_tree, template, msg_bld_t)
242
brians343bc112013-02-10 01:53:46 +0000243 end
244 def DefineMembers(cpp_tree, template, msg_bld_t)
245 send = template.def_func("bool","Send")
246 send.suite << CPP::Return.new("msg_ptr_.Send()")
247 @members.each do |elem|
248=begin
249 MessageBuilder<frc971::control_loops::Drivetrain::Goal> &steering(
250 double steering) {
251 msg_ptr_->steering = steering;
252 return *this;
253 }
254=end
255 setter = template.def_func(msg_bld_t,"&#{elem.name}")
256 setter.args << elem.create_usage(cpp_tree)
257 elem.set_message_builder(setter.suite)
258 setter.suite << CPP::Return.new("*this")
259
260 end
261 end
brians343bc112013-02-10 01:53:46 +0000262end
263class Target::MessageElement < Target::Node
264 attr_accessor :name,:loc,:size,:zero,:type,:printformat
265 def initialize(type,name)
266 @type,@name = type,name
267 end
268 def toPrintFormat()
269 return printformat
270 end
271 def create_usage(cpp_tree)
272 "#{@type} #{@name}"
273 end
Parker Schuh343481e2014-02-09 18:28:43 -0800274 def toNetwork(offset,suite, parent = "")
brians343bc112013-02-10 01:53:46 +0000275 suite << f_call = CPP::FuncCall.build("to_network",
Parker Schuh343481e2014-02-09 18:28:43 -0800276 "&#{parent}#{@name}",
Brian Silverman16c82972014-02-13 15:36:40 -0800277 "&buffer[#{offset}]")
brians343bc112013-02-10 01:53:46 +0000278 f_call.args.dont_wrap = true
279 end
Parker Schuh343481e2014-02-09 18:28:43 -0800280 def toHost(offset,suite, parent = "")
brians343bc112013-02-10 01:53:46 +0000281 suite << f_call = CPP::FuncCall.build("to_host",
Brian Silverman16c82972014-02-13 15:36:40 -0800282 "&buffer[#{offset}]",
Parker Schuh343481e2014-02-09 18:28:43 -0800283 "&#{parent}#{@name}")
brians343bc112013-02-10 01:53:46 +0000284 f_call.args.dont_wrap = true
285 end
Parker Schuh711db3e2014-02-12 09:47:34 -0800286 def getTypeID()
Brian Silverman1885bd02014-02-13 12:28:12 -0800287 Digest::SHA1.hexdigest(@type)[0..7].to_i(16) |
288 0x2000 | # marks it as primitive
289 size
Parker Schuh711db3e2014-02-12 09:47:34 -0800290 end
291 def simpleStr()
292 "#{@type} #{@name}"
293 end
brians343bc112013-02-10 01:53:46 +0000294 def set_message_builder(suite)
295 suite << "msg_ptr_->#{@name} = #{@name}"
296 end
297
Parker Schuh343481e2014-02-09 18:28:43 -0800298 def zeroCall(suite, parent = "")
299 suite << CPP::Assign.new(parent + @name,@zero)
300 end
301 def fetchPrintArgs(args, parent = "")
302 if (self.type == 'bool')
303 args.push("#{parent}#{self.name} ? 'T' : 'f'")
304 else
305 args.push("#{parent}#{self.name}")
306 end
brians343bc112013-02-10 01:53:46 +0000307 end
308end
309class Target::MessageArrayElement < Target::Node
310 attr_accessor :name,:loc,:size,:zero,:type
311 def initialize(type,name,length)
312 @type,@name,@length = type,name,length
313 end
314 def create_usage(cpp_tree)
315 "#{@type} #{@name}[#@length]"
316 end
317 def type()
318 "#{@type}[#@length]"
319 end
320 def size()
321 @size * @length
322 end
323 def toNetwork(offset,suite)
324 offset = (offset == 0) ? "" : "#{offset} + "
325 suite << for_stmt = CPP::For.new("int i = 0","i < #{@length}","i++")
326 for_stmt.suite << f_call = CPP::FuncCall.build("to_network",
327 "&(#{@name}[i])",
328 "&buffer[i + #{offset}::aos::Message::Size()]")
329 f_call.args.dont_wrap = true
330 end
331 def toHost(offset,suite)
332 offset = (offset == 0) ? "" : "#{offset} + "
333 suite << for_stmt = CPP::For.new("int i = 0","i < #{@length}","i++")
334 for_stmt.suite << f_call = CPP::FuncCall.build("to_host",
335 "&buffer[i + #{offset}::aos::Message::Size()]",
336 "&(#{@name}[i])")
337 f_call.args.dont_wrap = true
338 end
339 def set_message_builder(suite)
340 suite << "memcpy(msg_ptr_->#{@name},#{@name},#@length)"
341 end
342 def zeroCall(suite)
343 suite << "memset(#@name,0,#{size()})"
344 end
345end