cosmos 3.3.3 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +2 -0
  3. data/.travis.yml +2 -1
  4. data/Gemfile +4 -3
  5. data/Manifest.txt +22 -0
  6. data/autohotkey/tools/handbook_creator.ahk +9 -0
  7. data/autohotkey/tools/packet_viewer.ahk +4 -0
  8. data/bin/exchndl20-x64.dll +0 -0
  9. data/bin/exchndl20.dll +0 -0
  10. data/bin/exchndl21-x64.dll +0 -0
  11. data/bin/exchndl21.dll +0 -0
  12. data/bin/exchndl22-x64.dll +0 -0
  13. data/bin/exchndl22.dll +0 -0
  14. data/bin/mgwhelp-x64.dll +0 -0
  15. data/bin/mgwhelp.dll +0 -0
  16. data/cosmos.gemspec +1 -0
  17. data/data/crc.txt +30 -24
  18. data/demo/config/data/crc.txt +3 -3
  19. data/demo/config/tools/handbook_creator/templates/command_packets.html.erb +3 -1
  20. data/demo/config/tools/handbook_creator/templates/telemetry_packets.html.erb +3 -1
  21. data/demo/procedures/cosmos_api_test.rb +1 -1
  22. data/ext/cosmos/ext/low_fragmentation_array/low_fragmentation_array.c +4 -0
  23. data/ext/cosmos/ext/platform/platform.c +22 -2
  24. data/ext/cosmos/ext/structure/structure.c +631 -104
  25. data/ext/cosmos/ext/telemetry/telemetry.c +3 -2
  26. data/lib/cosmos/gui/line_graph/line_graph_drawing.rb +71 -92
  27. data/lib/cosmos/gui/line_graph/overview_graph.rb +1 -1
  28. data/lib/cosmos/gui/qt.rb +38 -24
  29. data/lib/cosmos/gui/text/ruby_editor.rb +1 -1
  30. data/lib/cosmos/packets/binary_accessor.rb +1 -288
  31. data/lib/cosmos/packets/telemetry.rb +2 -1
  32. data/lib/cosmos/script/cmd_tlm_server.rb +110 -0
  33. data/lib/cosmos/script/commands.rb +166 -0
  34. data/lib/cosmos/script/extract.rb +2 -2
  35. data/lib/cosmos/script/limits.rb +108 -0
  36. data/lib/cosmos/script/script.rb +28 -1487
  37. data/lib/cosmos/script/scripting.rb +889 -0
  38. data/lib/cosmos/script/telemetry.rb +174 -0
  39. data/lib/cosmos/script/tools.rb +138 -0
  40. data/lib/cosmos/streams/stream_protocol.rb +9 -6
  41. data/lib/cosmos/system/target.rb +55 -38
  42. data/lib/cosmos/tools/cmd_tlm_server/api.rb +6 -3
  43. data/lib/cosmos/tools/cmd_tlm_server/connections.rb +0 -1
  44. data/lib/cosmos/tools/cmd_tlm_server/gui/interfaces_tab.rb +17 -7
  45. data/lib/cosmos/tools/cmd_tlm_server/interface_thread.rb +15 -4
  46. data/lib/cosmos/tools/handbook_creator/handbook_creator.rb +15 -8
  47. data/lib/cosmos/tools/handbook_creator/handbook_creator_config.rb +41 -13
  48. data/lib/cosmos/tools/packet_viewer/packet_viewer.rb +18 -1
  49. data/lib/cosmos/tools/tlm_viewer/widgets/canvasline_widget.rb +1 -1
  50. data/lib/cosmos/tools/tlm_viewer/widgets/canvaslinevalue_widget.rb +1 -1
  51. data/lib/cosmos/tools/tlm_viewer/widgets/limitsbar_widget.rb +1 -1
  52. data/lib/cosmos/tools/tlm_viewer/widgets/rangebar_widget.rb +1 -1
  53. data/lib/cosmos/top_level.rb +1 -1
  54. data/lib/cosmos/utilities/ruby_lex_utils.rb +1 -1
  55. data/lib/cosmos/version.rb +5 -5
  56. data/spec/gui/line_graph/line_clip_spec.rb +6 -6
  57. data/spec/gui/qt_spec.rb +102 -0
  58. data/spec/interfaces/interface_spec.rb +9 -9
  59. data/spec/interfaces/linc_interface_spec.rb +72 -15
  60. data/spec/interfaces/serial_interface_spec.rb +9 -9
  61. data/spec/interfaces/simulated_target_interface_spec.rb +7 -7
  62. data/spec/interfaces/stream_interface_spec.rb +4 -4
  63. data/spec/interfaces/tcpip_client_interface_spec.rb +8 -8
  64. data/spec/interfaces/tcpip_server_interface_spec.rb +9 -9
  65. data/spec/interfaces/udp_interface_spec.rb +20 -20
  66. data/spec/io/json_drb_spec.rb +4 -4
  67. data/spec/io/raw_logger_pair_spec.rb +20 -20
  68. data/spec/io/raw_logger_spec.rb +3 -3
  69. data/spec/io/tcpip_server_spec.rb +9 -9
  70. data/spec/io/udp_sockets_spec.rb +2 -2
  71. data/spec/io/win32_serial_driver_spec.rb +2 -2
  72. data/spec/packets/binary_accessor_spec.rb +143 -6
  73. data/spec/packets/commands_spec.rb +5 -5
  74. data/spec/packets/limits_spec.rb +15 -15
  75. data/spec/packets/packet_config_spec.rb +19 -19
  76. data/spec/packets/packet_item_limits_spec.rb +3 -3
  77. data/spec/packets/packet_item_spec.rb +4 -4
  78. data/spec/packets/packet_spec.rb +33 -33
  79. data/spec/packets/structure_item_spec.rb +19 -19
  80. data/spec/packets/telemetry_spec.rb +6 -6
  81. data/spec/script/cmd_tlm_server_spec.rb +110 -0
  82. data/spec/script/commands_disconnect_spec.rb +270 -0
  83. data/spec/script/commands_spec.rb +288 -0
  84. data/spec/script/limits_spec.rb +153 -0
  85. data/spec/script/script_spec.rb +32 -696
  86. data/spec/script/scripting_spec.rb +436 -0
  87. data/spec/script/telemetry_spec.rb +130 -0
  88. data/spec/script/tools_spec.rb +117 -0
  89. data/spec/spec_helper.rb +10 -5
  90. data/spec/streams/preidentified_stream_protocol_spec.rb +4 -4
  91. data/spec/streams/serial_stream_spec.rb +8 -8
  92. data/spec/streams/stream_protocol_spec.rb +4 -4
  93. data/spec/streams/tcpip_client_stream_spec.rb +3 -3
  94. data/spec/streams/tcpip_socket_stream_spec.rb +7 -7
  95. data/spec/streams/template_stream_protocol_spec.rb +1 -1
  96. data/spec/system/system_spec.rb +6 -6
  97. data/spec/system/target_spec.rb +2 -0
  98. data/spec/tools/cmd_tlm_server/api_spec.rb +17 -17
  99. data/spec/tools/cmd_tlm_server/cmd_tlm_server_config_spec.rb +5 -5
  100. data/spec/tools/cmd_tlm_server/interface_thread_spec.rb +3 -3
  101. data/spec/top_level/top_level_spec.rb +8 -8
  102. data/spec/utilities/csv_spec.rb +3 -3
  103. data/spec/utilities/message_log_spec.rb +3 -3
  104. data/spec/utilities/ruby_lex_utils_spec.rb +7 -7
  105. data/test/performance/config/tools/launcher/launcher_threads.txt +8 -1
  106. data/test/performance/tools/CmdTlmServerMemProf +1 -1
  107. data/test/performance/tools/TlmGrapherMemProf +19 -0
  108. data/test/performance/tools/TlmGrapherMemProf.bat +59 -0
  109. metadata +38 -2
@@ -171,8 +171,9 @@ static VALUE value(int argc, VALUE* argv, VALUE self)
171
171
  * can be passed which will convert all items the same way. Or
172
172
  * an array of symbols can be passed to control how each item is
173
173
  * converted.
174
- * @return [Array, Array] The first array contains the item values and the
175
- * second their limits state
174
+ * @return [Array, Array, Array] The first array contains the item values, the
175
+ * second their limits state, and the third the limits settings which includes
176
+ * red, yellow, and green (if given) limits values.
176
177
  */
177
178
  static VALUE values_and_limits_states(int argc, VALUE* argv, VALUE self) {
178
179
  VALUE item_array = Qnil;
@@ -33,7 +33,7 @@ module Cosmos
33
33
  calculate_scaling_factors()
34
34
 
35
35
  # Draw overall graph and origin lines
36
- clear_canvas_and_draw_graph_rectangle(@painter)
36
+ draw_graph_background(@painter)
37
37
  draw_origin_lines(@painter)
38
38
 
39
39
  # Draw gridlines and titles
@@ -45,7 +45,6 @@ module Cosmos
45
45
  draw_y_axis_title(@painter, :LEFT)
46
46
  draw_y_axis_title(@painter, :RIGHT)
47
47
 
48
- # Draw legend and lines
49
48
  draw_legend(@painter)
50
49
 
51
50
  draw_lines(@painter, :LEFT)
@@ -54,7 +53,6 @@ module Cosmos
54
53
 
55
54
  # Draws the graph to the screen
56
55
  def draw_graph_to_screen
57
- # Draw frame around graph
58
56
  draw_frame(@painter)
59
57
 
60
58
  # Draw cursor line and popups if present
@@ -64,16 +62,10 @@ module Cosmos
64
62
  draw_error_icon(@painter)
65
63
  end # def draw_graph_to_screen
66
64
 
67
- # Clears the entire canvas and then draws the colored rectangle for the graph
68
- def clear_canvas_and_draw_graph_rectangle(dc)
69
- # Draw graph background
70
- color = Cosmos::getColor(@graph_back_color)
71
- dc.setPen(color)
72
- dc.setBrush(Cosmos.getBrush(@@gradient))
73
- dc.drawRect(@graph_left_x,@graph_top_y,@graph_right_x - @graph_left_x,@graph_bottom_y - @graph_top_y)
74
- # Draw the graph border
75
- dc.addRectColor(@graph_left_x, @graph_top_y, @graph_right_x - @graph_left_x, @graph_bottom_y - @graph_top_y, @label_and_border_color)
76
- end # def clear_canvas_and_draw_graph_rectangle
65
+ # Draws the colored rectangle for the graph
66
+ def draw_graph_background(dc)
67
+ dc.addRectColorFill(@graph_left_x, @graph_top_y, @graph_right_x - @graph_left_x, @graph_bottom_y - @graph_top_y, @label_and_border_color, @@gradient)
68
+ end
77
69
 
78
70
  # Draws origin lines if they fall on the graph
79
71
  def draw_origin_lines(dc)
@@ -93,14 +85,19 @@ module Cosmos
93
85
 
94
86
  # Draws the gridlines for a y-axis
95
87
  def draw_y_axis_grid_lines(dc)
88
+ grid_lines = []
96
89
  @y_grid_lines.each_with_index do |value, index|
97
90
  # Don't draw gridlines that are too close to 0
98
91
  if ((value > (@y_grid_line_scale / 2.0)) || (value < (@y_grid_line_scale / -2.0)))
99
- draw_y_label_and_grid_line(dc, value, index, true)
92
+ grid_lines << draw_y_label(dc, value, index)
100
93
  else
101
- draw_y_label_and_grid_line(dc, 0, index, true)
94
+ grid_lines << draw_y_label(dc, 0, index)
102
95
  end
103
96
  end
97
+ # Now draw all the grid lines so we can use a single Pen for all
98
+ grid_lines.each do |y|
99
+ dc.addLineColor(@graph_left_x, y, @graph_right_x, y, Cosmos::DASHLINE_PEN)
100
+ end
104
101
  end # def draw_y_axis_grid_lines
105
102
 
106
103
  # Calcuate the Y axis labels as well as their width and adjust the size of
@@ -144,10 +141,8 @@ module Cosmos
144
141
  @graph_right_x -= (right_widths.max + GRAPH_SPACER)
145
142
  end
146
143
 
147
- # This function is used to draw a horizontal line on the graph with a label.
148
- # This line is not clipped so the value must fall on the graph. Uses the
149
- # label values calculated in calculate_y_labels.
150
- def draw_y_label_and_grid_line(dc, value, index, show_line)
144
+ # This function is used to draw the y labels.
145
+ def draw_y_label(dc, value, index)
151
146
  left_value = value
152
147
  right_value = value
153
148
  left_text = @left_text[index]
@@ -193,28 +188,29 @@ module Cosmos
193
188
  y + (@font_size / 2))
194
189
  end
195
190
  end
196
-
197
- if show_line and y
198
- dc.addLineColor(@graph_left_x, y, @graph_right_x, y, Cosmos::DASHLINE_PEN)
199
- end
200
-
201
- end # def draw_y_label_and_grid_line
191
+ return y
192
+ end
202
193
 
203
194
  # Draws the gridlines for the x-axis
204
195
  def draw_x_axis_grid_lines(dc)
196
+ grid_lines = []
205
197
  @x_grid_lines.each do |value, label|
206
198
  # If the line has states or is far enough away from the origin
207
199
  if @lines.x_states || ((value > (@x_grid_line_scale / 2.0)) || (value < (@x_grid_line_scale / -2.0)))
208
- draw_x_label_and_grid_line(dc, value, label, true)
200
+ grid_lines << draw_x_label(dc, value, label)
209
201
  else
210
- draw_x_label_and_grid_line(dc, 0, nil, true)
202
+ grid_lines << draw_x_label(dc, 0, nil)
211
203
  end
212
204
  end
205
+ # Now draw all the grid lines so we can use a single Pen for all
206
+ grid_lines.each do |x1, y1, x2, y2|
207
+ dc.addLineColor(x1, y1, x2, y2, Cosmos::DASHLINE_PEN)
208
+ end
213
209
  end # def draw_x_axis_grid_lines
214
210
 
215
- # This function is used to draw a vertical line on the graph with a label.
216
- # This line is not clipped so the value must fall on the graph
217
- def draw_x_label_and_grid_line(dc, value, label, show_line)
211
+ # This function is used to draw the x labels and returns the line
212
+ # positions.
213
+ def draw_x_label(dc, value, label)
218
214
  if label
219
215
  text = label.to_s
220
216
  else
@@ -231,13 +227,8 @@ module Cosmos
231
227
  if (x1 > @graph_right_x)
232
228
  x1 = @graph_right_x
233
229
  end
234
- if show_line
235
- y2 = @graph_top_y
236
- else
237
- y2 = @graph_bottom_y
238
- end
230
+ y2 = @graph_top_y
239
231
  x2 = x1
240
- dc.addLineColor(x1, y1, x2, y2, Cosmos::DASHLINE_PEN)
241
232
 
242
233
  # Only display the label if we have room. This really only affects the
243
234
  # right side of the graph since that's where new grid lines appear. The
@@ -245,10 +236,11 @@ module Cosmos
245
236
  # white space on the right side of the graph.
246
237
  if (x1 == @graph_right_x) || (x1 < (@graph_right_x - (1.25 * text_width)))
247
238
  # Shift the far right label left a bit to eliminate white space
248
- x1 -= text_width / 4 if x1 == @graph_right_x
249
- x1 -= text_width / 2 # center the text
250
- dc.addSimpleTextAt(text, x1, @graph_bottom_y + text_height + GRAPH_SPACER)
239
+ text_x = x1 - text_width / 4 if x1 == @graph_right_x
240
+ text_x = x1 - text_width / 2 # center the text
241
+ dc.addSimpleTextAt(text, text_x, @graph_bottom_y + text_height + GRAPH_SPACER)
251
242
  end
243
+ [x1, y1, x2, y2]
252
244
  end # def draw_x_label_and_grid_line
253
245
 
254
246
  # Converts a x value into text with a max number of characters
@@ -286,7 +278,7 @@ module Cosmos
286
278
  end
287
279
  end
288
280
 
289
- # Draw the overall graph title
281
+ # Draw the overall graph title above the graph
290
282
  def draw_title(dc)
291
283
  if @title
292
284
  metrics = Cosmos.getFontMetrics(@title_font)
@@ -294,9 +286,9 @@ module Cosmos
294
286
  dc.addSimpleTextAt(@title, (self.width / 2) - (metrics.width(@title) / 2), metrics.height)
295
287
  dc.setFont(@font)
296
288
  end
297
- end # def draw_title
289
+ end
298
290
 
299
- # Draws the title for the X-axis
291
+ # Draws the x axis title below the graph
300
292
  def draw_x_axis_title(dc)
301
293
  if @x_axis_title
302
294
  metrics = Cosmos.getFontMetrics(@font)
@@ -306,9 +298,9 @@ module Cosmos
306
298
  (((@graph_right_x - @graph_left_x) / 2) + @graph_left_x) - (text_width / 2),
307
299
  @graph_bottom_y + (2 * text_height) + GRAPH_SPACER)
308
300
  end
309
- end # def draw_x_axis_title
301
+ end
310
302
 
311
- # Draws a title for a Y-axis
303
+ # Draws titles to the left and right of the Y axis
312
304
  def draw_y_axis_title(dc, axis)
313
305
  metrics = Cosmos.getFontMetrics(@font)
314
306
  if axis == :LEFT
@@ -330,58 +322,46 @@ module Cosmos
330
322
  dc.addSimpleTextAt(character, graph_x + ((max_width - cur_width) / 2), start_height + text_height * index)
331
323
  end
332
324
  end
333
- end # def draw_y_axis_title
325
+ end
334
326
 
335
327
  # Draws the legend on the bottom of the graph
336
328
  def draw_legend(dc)
329
+ return if !@show_legend || @lines.empty?
330
+
331
+ text_x, text_y, legend_width, legend_height = get_legend_position()
332
+ if @lines.axes == :BOTH
333
+ draw_legend_text(dc, :LEFT, text_x, text_y, legend_height)
334
+ draw_legend_text(dc, :RIGHT, text_x + (legend_width / 2), text_y, legend_height)
335
+ else
336
+ draw_legend_text(dc, false, text_x, text_y, legend_height)
337
+ end
338
+ end
339
+
340
+ # Calculate the legend x, y, width and height
341
+ def get_legend_position
337
342
  metrics = Cosmos.getFontMetrics(@font)
338
- # Draw Legend
339
- if @show_legend && !@lines.empty?
340
- if @lines.axes == :BOTH
341
- both_axis = true
342
- else
343
- both_axis = false
344
- end
345
- legend_width = 0
346
- @lines.legend.each do |legend_text, color, axis|
347
- text_width = metrics.width(legend_text)
348
- legend_width = text_width if text_width > legend_width
349
- end
350
- legend_width += (GRAPH_SPACER * 2)
351
- legend_width *= 2 if both_axis
352
- legend_graph_x = (self.width - legend_width) / 2
353
-
354
- text_x = legend_graph_x + GRAPH_SPACER
355
- text_y = self.height - metrics.height
356
-
357
- # Draw legend text for each line
358
- if both_axis
359
- left_text_x = text_x
360
- right_text_x = text_x + (legend_width / 2)
361
- left_text_y = text_y
362
- right_text_y = text_y
363
- @lines.legend.reverse_each do |legend_text, color, axis|
364
- if axis == :LEFT
365
- dc.addSimpleTextAt(legend_text, left_text_x, left_text_y, color)
366
- left_text_y -= metrics.height
367
- else
368
- dc.addSimpleTextAt(legend_text, right_text_x, right_text_y, color)
369
- right_text_y -= metrics.height
370
- end
371
- end
372
- if left_text_y < right_text_y
373
- text_y = left_text_y
374
- else
375
- text_y = right_text_y
376
- end
377
- else
378
- @lines.legend.reverse_each do |legend_text, color, axis|
379
- dc.addSimpleTextAt(legend_text, text_x, text_y, color)
380
- text_y -= metrics.height
381
- end
343
+ legend_width = 0
344
+ @lines.legend.each do |legend_text, color, axis|
345
+ text_width = metrics.width(legend_text)
346
+ legend_width = text_width if text_width > legend_width
347
+ end
348
+ legend_width += (GRAPH_SPACER * 2)
349
+ legend_width *= 2 if @lines.axes == :BOTH
350
+ legend_graph_x = (self.width - legend_width) / 2
351
+
352
+ text_x = legend_graph_x + GRAPH_SPACER
353
+ text_y = self.height - metrics.height
354
+ return [text_x, text_y, legend_width, metrics.height]
355
+ end
356
+
357
+ def draw_legend_text(dc, specific_axis, text_x, text_y, line_height)
358
+ @lines.legend.reverse_each do |legend_text, color, axis|
359
+ if !specific_axis || specific_axis == axis
360
+ dc.addSimpleTextAt(legend_text, text_x, text_y, color)
361
+ text_y -= line_height
382
362
  end
383
363
  end
384
- end # def draw_legend
364
+ end
385
365
 
386
366
  # Draws all lines for the given axis
387
367
  # def draw_lines(dc, axis)
@@ -438,9 +418,8 @@ module Cosmos
438
418
  end # unless popups.empty?
439
419
  end
440
420
 
441
- # Draws the overall frame around the canvas
421
+ # Draws the overall frame around the graph, legend, labels, etc
442
422
  def draw_frame(dc)
443
- # Draw Frame Rectangle around canvas
444
423
  dc.addRectColor(0,0,self.width-1,self.height-1, @frame_color)
445
424
  end
446
425
 
@@ -400,7 +400,7 @@ module Cosmos
400
400
 
401
401
  def draw_graph_into_back_buffer
402
402
  # Draw overall graph and origin lines and graph lines
403
- clear_canvas_and_draw_graph_rectangle(@painter)
403
+ draw_graph_background(@painter)
404
404
  draw_origin_lines(@painter)
405
405
  draw_lines(@painter, :LEFT)
406
406
 
@@ -94,6 +94,7 @@ module Cosmos
94
94
  color = nil
95
95
  key = color_r
96
96
  key = key.to_i if key.is_a? Qt::Enum
97
+
97
98
  if color_r && color_g && color_b
98
99
  key = (color_r.to_i << 24) + (color_g.to_i << 16) + (color_b.to_i << 8)
99
100
  end
@@ -112,6 +113,8 @@ module Cosmos
112
113
  end
113
114
 
114
115
  def self.getBrush(color)
116
+ return nil unless color
117
+ return color if color.is_a? Qt::Brush
115
118
  brush = nil
116
119
  color = Cosmos.getColor(color)
117
120
  brush = BRUSHES[color]
@@ -280,10 +283,16 @@ class Qt::TableWidget
280
283
  resizeRowsToContents()
281
284
  setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff)
282
285
  setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff)
283
- setMinimumSize(2*frameWidth() + horizontalHeader.length + verticalHeader.width,
284
- 2*frameWidth() + verticalHeader.length + horizontalHeader.height)
285
- setMaximumSize(2*frameWidth() + horizontalHeader.length + verticalHeader.width,
286
- 2*frameWidth() + verticalHeader.length + horizontalHeader.height)
286
+ setMinimumSize(fullWidth, fullHeight)
287
+ setMaximumSize(fullWidth, fullHeight)
288
+ end
289
+
290
+ def fullWidth
291
+ 2*frameWidth() + horizontalHeader.length + verticalHeader.width
292
+ end
293
+
294
+ def fullHeight
295
+ 2*frameWidth() + verticalHeader.length + horizontalHeader.height
287
296
  end
288
297
  end
289
298
 
@@ -669,47 +678,52 @@ class Qt::ColorListWidget < Qt::ListWidget
669
678
  end
670
679
 
671
680
  class Qt::Painter
681
+ def setPen(pen_color)
682
+ super(Cosmos::getColor(pen_color))
683
+ @pen_color = pen_color
684
+ end
685
+ def setBrush(brush)
686
+ super(Cosmos::getBrush(brush))
687
+ @brush = brush
688
+ end
689
+
672
690
  def addLineColor(x, y, w, h, color = Cosmos::BLACK)
673
- setPenColor(color)
691
+ setPen(color) if color != @pen_color
674
692
  drawLine(x,y,w,h)
675
693
  end
676
694
 
677
695
  def addRectColor(x, y, w, h, color = Cosmos::BLACK)
678
- setPenColor(color)
679
- setBrush(nil)
696
+ setPen(color) if color != @pen_color
697
+ setBrush(nil) if @brush
680
698
  drawRect(x,y,w,h)
681
699
  end
682
700
 
683
- def addRectColorFill(x, y, w, h, color = Cosmos::BLACK)
684
- setPenColor(color)
685
- setBrush(Cosmos.getBrush(color))
701
+ # Note if brush_color is not specified it will be the same as pen_color
702
+ def addRectColorFill(x, y, w, h, pen_color = Cosmos::BLACK, brush_color = nil)
703
+ setPen(pen_color) if pen_color != @pen_color
704
+ brush_color = pen_color unless brush_color
705
+ setBrush(brush_color) if brush_color != @brush
686
706
  drawRect(x,y,w,h)
687
707
  end
688
708
 
689
709
  def addSimpleTextAt(text, x, y, color = Cosmos::BLACK)
690
- setPenColor(color)
710
+ setPen(color) if color != @pen_color
691
711
  drawText(x,y,text)
692
712
  end
693
713
 
694
714
  def addEllipseColor(x, y, w, h, color = Cosmos::BLACK)
695
- setPenColor(color)
696
- setBrush(nil)
715
+ setPen(color) if color != @pen_color
716
+ setBrush(nil) if @brush
697
717
  drawEllipse(x,y,w,h)
698
718
  end
699
719
 
700
- def addEllipseColorFill(x, y, w, h, color = Cosmos::BLACK)
701
- setPenColor(color)
702
- setBrush(Cosmos.getBrush(color))
720
+ # Note if brush_color is not specified it will be the same as pen_color
721
+ def addEllipseColorFill(x, y, w, h, pen_color = Cosmos::BLACK, brush_color = nil)
722
+ setPen(pen_color) if pen_color != @pen_color
723
+ brush_color = pen_color unless brush_color
724
+ setBrush(brush_color) if brush_color != @brush
703
725
  drawEllipse(x,y,w,h)
704
726
  end
705
-
706
- private
707
-
708
- def setPenColor(color)
709
- color = Cosmos::getColor(color)
710
- setPen(color)
711
- end
712
-
713
727
  end
714
728
 
715
729
  class Qt::MatrixLayout < Qt::GridLayout
@@ -363,7 +363,7 @@ module Cosmos
363
363
  number.to_s) # text
364
364
 
365
365
  if @enable_breakpoints and @breakpoints.include?(number)
366
- painter.setBrush(Cosmos.getBrush(Cosmos::RED))
366
+ painter.setBrush(Cosmos::RED)
367
367
  painter.drawEllipse(2,
368
368
  top+2,
369
369
  ellipse_width,
@@ -111,294 +111,7 @@ module Cosmos
111
111
  # @param endianness [Symbol] {ENDIANNESS}
112
112
  # @param overflow [Symbol] {OVERFLOW_TYPES}
113
113
  # @return [Integer] value passed in as a parameter
114
- def self.write(value, bit_offset, bit_size, data_type, buffer, endianness, overflow)
115
- # Save given values of bit offset and bit size
116
- given_bit_offset = bit_offset
117
- given_bit_size = bit_size
118
-
119
- # Handle negative and zero bit sizes
120
- if bit_size <= 0
121
- if data_type == :STRING or data_type == :BLOCK
122
- if given_bit_offset < 0
123
- raise ArgumentError, "negative or zero bit_sizes (#{given_bit_size}) cannot be given with negative bit_offsets (#{given_bit_offset})"
124
- else
125
- bit_size = value.to_s.length * 8
126
- end
127
- else
128
- raise ArgumentError, "bit_size #{given_bit_size} must be positive for data types other than :STRING and :BLOCK"
129
- end
130
- end
131
-
132
- # Handle negative bit offsets
133
- if bit_offset < 0
134
- bit_offset = ((buffer.length * 8) + bit_offset)
135
- raise_buffer_error(:write, buffer, data_type, given_bit_offset, given_bit_size) if bit_offset < 0
136
- end
137
-
138
- # Define bounds of string to access this item
139
- lower_bound = bit_offset / 8
140
- upper_bound = (bit_offset + bit_size - 1) / 8
141
-
142
- # Check for byte alignment
143
- byte_aligned = ((bit_offset % 8) == 0)
144
-
145
- # Sanity check buffer size
146
- if upper_bound >= buffer.length and given_bit_size > 0
147
- # Check special case of little endian bit field
148
- if endianness == :LITTLE_ENDIAN and (data_type == :INT or data_type == :UINT) and !(byte_aligned and (bit_size == 8 or bit_size == 16 or bit_size == 32 or bit_size == 64)) and lower_bound < buffer.length
149
- # Ok little endian bit field
150
- else
151
- raise_buffer_error(:write, buffer, data_type, given_bit_offset, given_bit_size)
152
- end
153
- end
154
-
155
- # Check overflow type
156
- raise "unknown overflow type #{overflow}" unless OVERFLOW_TYPES.include?(overflow)
157
-
158
- case data_type
159
- when :STRING, :BLOCK
160
- #######################################
161
- # Handle :STRING and :BLOCK data types
162
- #######################################
163
-
164
- # Ensure value is the correct type
165
- value = value.to_s
166
-
167
- if byte_aligned
168
- temp = value
169
- if given_bit_size <= 0
170
- end_bytes = -(given_bit_size / 8)
171
- old_upper_bound = buffer.length - 1 - end_bytes
172
- if old_upper_bound < lower_bound
173
- # String was completely empty
174
- if end_bytes > 0
175
- # Preserve bytes at end of buffer
176
- buffer_length = buffer.length
177
- buffer << ZERO_STRING * value.length
178
- buffer[(lower_bound + value.length)..(buffer.length - 1)] = buffer[lower_bound..(buffer_length - 1)]
179
- end
180
- elsif bit_size == 0
181
- # Remove entire string
182
- buffer[lower_bound..old_upper_bound] = ''
183
- elsif upper_bound < old_upper_bound
184
- # Remove extra bytes from old string
185
- buffer[(upper_bound + 1)..old_upper_bound] = ''
186
- elsif upper_bound > old_upper_bound and end_bytes > 0
187
- # Preserve bytes at end of buffer
188
- buffer_length = buffer.length
189
- diff = upper_bound - old_upper_bound
190
- buffer << ZERO_STRING * diff
191
- buffer[(upper_bound + 1)..(buffer.length - 1)] = buffer[(old_upper_bound + 1)..(buffer_length - 1)]
192
- end
193
- else
194
- byte_size = bit_size / 8
195
- if value.length < byte_size
196
- temp = value.ljust(byte_size, ZERO_STRING)
197
- elsif value.length > byte_size
198
- if overflow == :TRUNCATE
199
- temp = value[0..(byte_size - 1)]
200
- else
201
- raise ArgumentError, "value of #{value.length} bytes does not fit into #{byte_size} bytes for data_type #{data_type}"
202
- end
203
- else
204
- temp = value
205
- end
206
- end
207
- buffer[lower_bound..upper_bound] = temp if bit_size != 0
208
- else
209
- raise ArgumentError, "bit_offset #{given_bit_offset} is not byte aligned for data_type #{data_type}"
210
- end
211
-
212
- when :INT, :UINT
213
- ###################################
214
- # Handle :INT and :UINT data types
215
- ###################################
216
-
217
- # Ensure value is the correct type
218
- value = Integer(value)
219
-
220
- if byte_aligned and (bit_size == 8 or bit_size == 16 or bit_size == 32 or bit_size == 64)
221
- ###########################################################
222
- # Handle byte-aligned 8, 16, 32, and 64 bit :INT and :UINT
223
- ###########################################################
224
-
225
- case bit_size
226
- when 8
227
- if data_type == :INT
228
- value = self.check_overflow(value, -128, 127, 255, bit_size, data_type, overflow)
229
- else
230
- value = self.check_overflow(value, 0, 255, 255, bit_size, data_type, overflow)
231
- end
232
- buffer.setbyte(lower_bound, value % 256)
233
-
234
- when 16
235
- if data_type == :INT
236
- value = self.check_overflow(value, -32768, 32767, 65535, bit_size, data_type, overflow)
237
- if endianness == HOST_ENDIANNESS
238
- buffer[lower_bound..upper_bound] = [value].pack(PACK_NATIVE_16_BIT_INT)
239
- else # endianness != HOST_ENDIANNESS
240
- buffer[lower_bound..upper_bound] = [value].pack(PACK_NATIVE_16_BIT_INT).reverse
241
- end
242
- else # data_type == :UINT
243
- value = self.check_overflow(value, 0, 65535, 65535, bit_size, data_type, overflow)
244
- if endianness == :BIG_ENDIAN
245
- buffer[lower_bound..upper_bound] = [value].pack(PACK_BIG_ENDIAN_16_BIT_UINT)
246
- else # endianness == :LITTLE_ENDIAN
247
- buffer[lower_bound..upper_bound] = [value].pack(PACK_LITTLE_ENDIAN_16_BIT_UINT)
248
- end
249
- end
250
-
251
- when 32
252
- if data_type == :INT
253
- # Note signed integers must allow up to the maximum unsigned value to support values given in hex
254
- value = self.check_overflow(value, -2147483648, 2147483647, 4294967295, bit_size, data_type, overflow)
255
- if endianness == HOST_ENDIANNESS
256
- buffer[lower_bound..upper_bound] = [value].pack(PACK_NATIVE_32_BIT_INT)
257
- else # endianness != HOST_ENDIANNESS
258
- buffer[lower_bound..upper_bound] = [value].pack(PACK_NATIVE_32_BIT_INT).reverse
259
- end
260
- elsif data_type == :UINT
261
- value = self.check_overflow(value, 0, 4294967295, 4294967295, bit_size, data_type, overflow)
262
- if endianness == :BIG_ENDIAN
263
- buffer[lower_bound..upper_bound] = [value].pack(PACK_BIG_ENDIAN_32_BIT_UINT)
264
- else # endianness == :LITTLE_ENDIAN
265
- buffer[lower_bound..upper_bound] = [value].pack(PACK_LITTLE_ENDIAN_32_BIT_UINT)
266
- end
267
- end
268
-
269
- when 64
270
- if data_type == :INT
271
- # Note signed integers must allow up to the maximum unsigned value to support values given in hex
272
- value = self.check_overflow(value, -9223372036854775808, 9223372036854775807, 18446744073709551615, bit_size, data_type, overflow)
273
- if endianness == HOST_ENDIANNESS
274
- buffer[lower_bound..upper_bound] = [value].pack(PACK_NATIVE_64_BIT_INT)
275
- else # endianness != HOST_ENDIANNESS
276
- buffer[lower_bound..upper_bound] = [value].pack(PACK_NATIVE_64_BIT_INT).reverse
277
- end
278
- elsif data_type == :UINT
279
- value = self.check_overflow(value, 0, 18446744073709551615, 18446744073709551615, bit_size, data_type, overflow)
280
- if endianness == HOST_ENDIANNESS
281
- buffer[lower_bound..upper_bound] = [value].pack(PACK_NATIVE_64_BIT_UINT)
282
- else # endianness != HOST_ENDIANNESS
283
- buffer[lower_bound..upper_bound] = [value].pack(PACK_NATIVE_64_BIT_UINT).reverse
284
- end
285
- end
286
- end
287
-
288
- else
289
- ##################################
290
- # Handle :INT and :UINT Bitfields
291
- ##################################
292
-
293
- if data_type == :INT
294
- # Note signed integers must allow up to the maximum unsigned value to support values given in hex
295
- if bit_size > 1
296
- min_value = -(2 ** (bit_size - 1))
297
- max_value = -min_value - 1
298
- hex_max_value = (2 ** bit_size) - 1
299
- else
300
- min_value = -1
301
- max_value = 1
302
- hex_max_value = 1
303
- end
304
- value = self.check_overflow(value, min_value, max_value, hex_max_value, bit_size, data_type, overflow)
305
- else
306
- max_value = (2 ** bit_size) - 1
307
- value = self.check_overflow(value, 0, max_value, max_value, bit_size, data_type, overflow)
308
- end
309
-
310
- # Extract Existing Data
311
- if endianness == :LITTLE_ENDIAN
312
- # Bitoffset always refers to the most significant bit of a bitfield
313
- num_bytes = (((bit_offset % 8) + bit_size - 1) / 8) + 1
314
- upper_bound = bit_offset / 8
315
- lower_bound = upper_bound - num_bytes + 1
316
-
317
- if lower_bound < 0
318
- raise ArgumentError, "LITTLE_ENDIAN bitfield with bit_offset #{given_bit_offset} and bit_size #{given_bit_size} is invalid"
319
- end
320
-
321
- temp_data = buffer[lower_bound..upper_bound].reverse
322
- else
323
- temp_data = buffer[lower_bound..upper_bound]
324
- end
325
-
326
- # Determine temp upper bound
327
- temp_upper = upper_bound - lower_bound
328
-
329
- # Determine Values needed to Handle Bitfield
330
- start_bits = bit_offset % 8
331
- start_mask = (0xFF << (8 - start_bits))
332
- total_bits = (temp_upper + 1) * 8
333
- end_bits = total_bits - start_bits - bit_size
334
- end_mask = ~(0xFF << end_bits)
335
-
336
- # Add in Start Bits
337
- temp = temp_data.getbyte(0) & start_mask
338
-
339
- # Adjust value to correct number of bits
340
- temp_mask = (2 ** bit_size) - 1
341
- temp_value = value.to_i & temp_mask
342
-
343
- # Add in New Data
344
- temp = (temp << (bit_size - (8 - start_bits))) + temp_value
345
-
346
- # Add in Remainder of Existing Data
347
- temp = (temp << end_bits) + (temp_data.getbyte(temp_upper) & end_mask)
348
-
349
- # Extract into an array of bytes
350
- temp_array = []
351
- (0..temp_upper).each { temp_array.insert(0, (temp & 0xFF)); temp = temp >> 8 }
352
-
353
- # Store into buffer
354
- if endianness == :LITTLE_ENDIAN
355
- buffer[lower_bound..upper_bound] = temp_array.pack(PACK_8_BIT_UINT_ARRAY).reverse
356
- else
357
- buffer[lower_bound..upper_bound] = temp_array.pack(PACK_8_BIT_UINT_ARRAY)
358
- end
359
- end
360
-
361
- when :FLOAT
362
- ##########################
363
- # Handle :FLOAT data type
364
- ##########################
365
-
366
- # Ensure value is the correct type
367
- value = Float(value)
368
-
369
- if byte_aligned
370
- case bit_size
371
- when 32
372
- if endianness == :BIG_ENDIAN
373
- buffer[lower_bound..upper_bound] = [value].pack(PACK_BIG_ENDIAN_32_BIT_FLOAT)
374
- else # endianness == :LITTLE_ENDIAN
375
- buffer[lower_bound..upper_bound] = [value].pack(PACK_LITTLE_ENDIAN_32_BIT_FLOAT)
376
- end
377
-
378
- when 64
379
- if endianness == :BIG_ENDIAN
380
- buffer[lower_bound..upper_bound] = [value].pack(PACK_BIG_ENDIAN_64_BIT_FLOAT)
381
- else # endianness == :LITTLE_ENDIAN
382
- buffer[lower_bound..upper_bound] = [value].pack(PACK_LITTLE_ENDIAN_64_BIT_FLOAT)
383
- end
384
-
385
- else
386
- raise ArgumentError, "bit_size is #{given_bit_size} but must be 32 or 64 for data_type #{data_type}"
387
- end
388
- else
389
- raise ArgumentError, "bit_offset #{given_bit_offset} is not byte aligned for data_type #{data_type}"
390
- end
391
-
392
- else
393
- ############################
394
- # Handle Unknown data types
395
- ############################
396
-
397
- raise ArgumentError, "data_type #{data_type} is not recognized"
398
- end
399
-
400
- value
401
- end # def self.write
114
+ # def self.write(value, bit_offset, bit_size, data_type, buffer, endianness, overflow)
402
115
 
403
116
  # Reads an array of binary data of any data type from a buffer
404
117
  #