Class: Cosmos::Interface

Inherits:
Object show all
Includes:
Api
Defined in:
lib/cosmos/interfaces/interface.rb

Overview

Defines all the attributes and methods common to all interface classes used by COSMOS.

Constant Summary

Constants included from ApiShared

ApiShared::DEFAULT_TLM_POLLING_RATE

Constants included from Extract

Extract::SCANNING_REGULAR_EXPRESSION

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Api

#cmd, #cmd_no_checks, #cmd_no_hazardous_check, #cmd_no_range_check, #cmd_raw, #cmd_raw_no_checks, #cmd_raw_no_hazardous_check, #cmd_raw_no_range_check, #cmd_tlm_clear_counters, #cmd_tlm_reload, #connect_interface, #connect_router, #disable_limits, #disable_limits_group, #disconnect_interface, #disconnect_router, #enable_limits, #enable_limits_group, #get_all_cmd_info, #get_all_interface_info, #get_all_packet_logger_info, #get_all_router_info, #get_all_target_info, #get_all_tlm_info, #get_background_tasks, #get_cmd_buffer, #get_cmd_cnt, #get_cmd_hazardous, #get_cmd_list, #get_cmd_log_filename, #get_cmd_param_list, #get_cmd_time, #get_cmd_value, #get_interface_info, #get_interface_names, #get_interface_targets, #get_limits, #get_limits_event, #get_limits_groups, #get_limits_set, #get_limits_sets, #get_out_of_limits, #get_output_logs_filenames, #get_overall_limits_state, #get_packet, #get_packet_data, #get_packet_logger_info, #get_packet_loggers, #get_router_info, #get_router_names, #get_saved_config, #get_screen_definition, #get_screen_list, #get_server_message, #get_server_message_log_filename, #get_server_status, #get_stale, #get_target_ignored_items, #get_target_ignored_parameters, #get_target_info, #get_target_list, #get_tlm_buffer, #get_tlm_cnt, #get_tlm_details, #get_tlm_item_list, #get_tlm_list, #get_tlm_log_filename, #get_tlm_packet, #get_tlm_values, #inject_tlm, #interface_state, #limits_enabled?, #map_target_to_interface, #normalize_tlm, #override_tlm_raw, #replay_move_end, #replay_move_index, #replay_move_start, #replay_play, #replay_reverse_play, #replay_select_file, #replay_set_playback_delay, #replay_status, #replay_step_back, #replay_step_forward, #replay_stop, #router_state, #send_raw, #set_limits, #set_limits_set, #set_tlm, #set_tlm_raw, #start_background_task, #start_cmd_log, #start_logging, #start_new_server_message_log, #start_raw_logging_interface, #start_raw_logging_router, #start_tlm_log, #stop_background_task, #stop_cmd_log, #stop_logging, #stop_raw_logging_interface, #stop_raw_logging_router, #stop_tlm_log, #subscribe_limits_events, #subscribe_packet_data, #subscribe_server_messages, #tlm, #tlm_formatted, #tlm_raw, #tlm_variable, #tlm_with_units, #unsubscribe_limits_events, #unsubscribe_packet_data, #unsubscribe_server_messages

Constructor Details

#initializeInterface

Initialize default attribute values



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/cosmos/interfaces/interface.rb', line 119

def initialize
  @name = self.class.to_s.split("::")[-1] # Remove namespacing if present
  @target_names = []
  @thread = nil
  @connect_on_startup = true
  @auto_reconnect = true
  @reconnect_delay = 5.0
  @disable_disconnect = false
  @packet_log_writer_pairs = []
  @stored_packet_log_writer_pairs = []
  @raw_logger_pair = RawLoggerPair.new(@name)
  @routers = []
  @cmd_routers = []
  @read_count = 0
  @write_count = 0
  @bytes_read = 0
  @bytes_written = 0
  @num_clients = 0
  @read_queue_size = 0
  @write_queue_size = 0
  @write_mutex = Mutex.new
  @interfaces = []
  @read_allowed = true
  @write_allowed = true
  @write_raw_allowed = true
  @options = {}
  @read_protocols = []
  @write_protocols = []
  @protocol_info = []
  @override_tlm = nil
  @read_raw_data = ''
  @written_raw_data = ''
  @read_raw_data_time = nil
  @written_raw_data_time = nil
end

Instance Attribute Details

#auto_reconnectBoolean

Returns Flag indicating if the interface should automatically reconnect after losing connection.

Returns:

  • (Boolean)

    Flag indicating if the interface should automatically reconnect after losing connection



37
38
39
# File 'lib/cosmos/interfaces/interface.rb', line 37

def auto_reconnect
  @auto_reconnect
end

#bytes_readInteger

Returns The number of bytes read from this interface.

Returns:

  • (Integer)

    The number of bytes read from this interface



70
71
72
# File 'lib/cosmos/interfaces/interface.rb', line 70

def bytes_read
  @bytes_read
end

#bytes_writtenInteger

Returns The number of bytes written to this interface.

Returns:

  • (Integer)

    The number of bytes written to this interface



73
74
75
# File 'lib/cosmos/interfaces/interface.rb', line 73

def bytes_written
  @bytes_written
end

#cmd_routersArray<Routers>

Returns Array of cmd routers that mirror packets sent from the interface.

Returns:

  • (Array<Routers>)

    Array of cmd routers that mirror packets sent from the interface



61
62
63
# File 'lib/cosmos/interfaces/interface.rb', line 61

def cmd_routers
  @cmd_routers
end

#connect_on_startupBoolean

Returns Flag indicating if the interface should be connected to on startup.

Returns:

  • (Boolean)

    Flag indicating if the interface should be connected to on startup



33
34
35
# File 'lib/cosmos/interfaces/interface.rb', line 33

def connect_on_startup
  @connect_on_startup
end

#disable_disconnectBoolean

Returns Flag indicating if the user is allowed to disconnect this interface.

Returns:

  • (Boolean)

    Flag indicating if the user is allowed to disconnect this interface



44
45
46
# File 'lib/cosmos/interfaces/interface.rb', line 44

def disable_disconnect
  @disable_disconnect
end

#interfacesArray<Interface>

Returns Array of interfaces to route packets to (when used as a Router).

Returns:

  • (Array<Interface>)

    Array of interfaces to route packets to (when used as a Router)



89
90
91
# File 'lib/cosmos/interfaces/interface.rb', line 89

def interfaces
  @interfaces
end

#nameString

Returns Name of the interface.

Returns:

  • (String)

    Name of the interface



23
24
25
# File 'lib/cosmos/interfaces/interface.rb', line 23

def name
  @name
end

#num_clientsInteger

Returns The number of active clients (when used as a Router).

Returns:

  • (Integer)

    The number of active clients (when used as a Router)



77
78
79
# File 'lib/cosmos/interfaces/interface.rb', line 77

def num_clients
  @num_clients
end

#optionsHash<option name, option values>

Returns Hash of options supplied to interface/router.

Returns:

  • (Hash<option name, option values>)

    Hash of options supplied to interface/router



92
93
94
# File 'lib/cosmos/interfaces/interface.rb', line 92

def options
  @options
end

#override_tlmHash or nil

Returns Hash of overridden telemetry points.

Returns:

  • (Hash or nil)

    Hash of overridden telemetry points



104
105
106
# File 'lib/cosmos/interfaces/interface.rb', line 104

def override_tlm
  @override_tlm
end

#packet_log_writer_pairsArray

Returns Array of packet logger classes for this interface.

Returns:

  • (Array)

    Array of packet logger classes for this interface



47
48
49
# File 'lib/cosmos/interfaces/interface.rb', line 47

def packet_log_writer_pairs
  @packet_log_writer_pairs
end

#protocol_infoArray<[Protocol Class, Protocol Args, Protocol kind (:READ, :WRITE, :READ_WRITE)>] Info to recreate protocols

Returns Array<[Protocol Class, Protocol Args, Protocol kind (:READ, :WRITE, :READ_WRITE)>] Info to recreate protocols.

Returns:

  • (Array<[Protocol Class, Protocol Args, Protocol kind (:READ, :WRITE, :READ_WRITE)>] Info to recreate protocols)

    Array<[Protocol Class, Protocol Args, Protocol kind (:READ, :WRITE, :READ_WRITE)>] Info to recreate protocols



101
102
103
# File 'lib/cosmos/interfaces/interface.rb', line 101

def protocol_info
  @protocol_info
end

#raw_logger_pairRawLoggerPair

Returns RawLoggerPair instance or nil.

Returns:



53
54
55
# File 'lib/cosmos/interfaces/interface.rb', line 53

def raw_logger_pair
  @raw_logger_pair
end

#read_countInteger

Returns The number of packets read from this interface.

Returns:

  • (Integer)

    The number of packets read from this interface



64
65
66
# File 'lib/cosmos/interfaces/interface.rb', line 64

def read_count
  @read_count
end

#read_protocolsArray<Protocol>

Returns Array of protocols for reading.

Returns:



95
96
97
# File 'lib/cosmos/interfaces/interface.rb', line 95

def read_protocols
  @read_protocols
end

#read_queue_sizeInteger

Returns The number of packets in the read queue (when used as a Router).

Returns:

  • (Integer)

    The number of packets in the read queue (when used as a Router)



81
82
83
# File 'lib/cosmos/interfaces/interface.rb', line 81

def read_queue_size
  @read_queue_size
end

#read_raw_dataString

Returns Most recently read raw data.

Returns:

  • (String)

    Most recently read raw data



107
108
109
# File 'lib/cosmos/interfaces/interface.rb', line 107

def read_raw_data
  @read_raw_data
end

#read_raw_data_timeTime

Returns Most recent read raw data time.

Returns:

  • (Time)

    Most recent read raw data time



113
114
115
# File 'lib/cosmos/interfaces/interface.rb', line 113

def read_raw_data_time
  @read_raw_data_time
end

#reconnect_delayInteger[ Delay between reconnect attempts

Returns Integer[ Delay between reconnect attempts.

Returns:

  • (Integer[ Delay between reconnect attempts)

    Integer[ Delay between reconnect attempts



40
41
42
# File 'lib/cosmos/interfaces/interface.rb', line 40

def reconnect_delay
  @reconnect_delay
end

#routersArray<Routers>

Returns Array of routers that receive packets read from the interface.

Returns:

  • (Array<Routers>)

    Array of routers that receive packets read from the interface



57
58
59
# File 'lib/cosmos/interfaces/interface.rb', line 57

def routers
  @routers
end

#stored_packet_log_writer_pairsArray

Returns Array of stored packet log writers.

Returns:

  • (Array)

    Array of stored packet log writers



50
51
52
# File 'lib/cosmos/interfaces/interface.rb', line 50

def stored_packet_log_writer_pairs
  @stored_packet_log_writer_pairs
end

#target_namesArray<String>

Returns Array of target names associated with this interface.

Returns:

  • (Array<String>)

    Array of target names associated with this interface



26
27
28
# File 'lib/cosmos/interfaces/interface.rb', line 26

def target_names
  @target_names
end

#threadThread

Returns Thread reading from the interface.

Returns:

  • (Thread)

    Thread reading from the interface



29
30
31
# File 'lib/cosmos/interfaces/interface.rb', line 29

def thread
  @thread
end

#write_countInteger

Returns The number of packets written to this interface.

Returns:

  • (Integer)

    The number of packets written to this interface



67
68
69
# File 'lib/cosmos/interfaces/interface.rb', line 67

def write_count
  @write_count
end

#write_protocolsArray<Protocol>

Returns Array of protocols for writing.

Returns:



98
99
100
# File 'lib/cosmos/interfaces/interface.rb', line 98

def write_protocols
  @write_protocols
end

#write_queue_sizeInteger

Returns The number of packets in the write queue (when used as a Router).

Returns:

  • (Integer)

    The number of packets in the write queue (when used as a Router)



85
86
87
# File 'lib/cosmos/interfaces/interface.rb', line 85

def write_queue_size
  @write_queue_size
end

#written_raw_dataString

Returns Most recently written raw data.

Returns:

  • (String)

    Most recently written raw data



110
111
112
# File 'lib/cosmos/interfaces/interface.rb', line 110

def written_raw_data
  @written_raw_data
end

#written_raw_data_timeTime

Returns Most recent written raw data time.

Returns:

  • (Time)

    Most recent written raw data time



116
117
118
# File 'lib/cosmos/interfaces/interface.rb', line 116

def written_raw_data_time
  @written_raw_data_time
end

Instance Method Details

#_normalize_tlm(target_name, packet_name, item_name) ⇒ Object



440
441
442
443
444
445
446
447
# File 'lib/cosmos/interfaces/interface.rb', line 440

def _normalize_tlm(target_name, packet_name, item_name)
  @override_tlm ||= {}
  pkt = @override_tlm[target_name]
  if pkt
    items = @override_tlm[target_name][packet_name]
    items.delete(item_name) if items
  end
end

#_override(target_name, packet_name, item_name, value, type) ⇒ Object



449
450
451
452
453
454
# File 'lib/cosmos/interfaces/interface.rb', line 449

def _override(target_name, packet_name, item_name, value, type)
  @override_tlm ||= {}
  @override_tlm[target_name] ||= {}
  @override_tlm[target_name][packet_name] ||= {}
  @override_tlm[target_name][packet_name][item_name] = [value, type]
end

#_override_tlm(target_name, packet_name, item_name, value) ⇒ Object



432
433
434
# File 'lib/cosmos/interfaces/interface.rb', line 432

def _override_tlm(target_name, packet_name, item_name, value)
  _override(target_name, packet_name, item_name, value, :CONVERTED)
end

#_override_tlm_raw(target_name, packet_name, item_name, value) ⇒ Object



436
437
438
# File 'lib/cosmos/interfaces/interface.rb', line 436

def _override_tlm_raw(target_name, packet_name, item_name, value)
  _override(target_name, packet_name, item_name, value, :RAW)
end

#_writeObject

Wrap all writes in a mutex and handle errors



285
286
287
288
289
290
291
292
293
294
295
# File 'lib/cosmos/interfaces/interface.rb', line 285

def _write
  if @write_mutex.owned?
    yield
  else
    @write_mutex.synchronize { yield }
  end
rescue Exception => err
  Logger.instance.error("Error writing to interface : #{@name}")
  disconnect()
  raise err
end

#add_protocol(protocol_class, protocol_args, read_write) ⇒ Object



414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
# File 'lib/cosmos/interfaces/interface.rb', line 414

def add_protocol(protocol_class, protocol_args, read_write)
  protocol_args = protocol_args.clone
  protocol = protocol_class.new(*protocol_args)
  case read_write
  when :READ
    @read_protocols << protocol
  when :WRITE
    @write_protocols.unshift(protocol)
  when :READ_WRITE
    @read_protocols << protocol
    @write_protocols.unshift(protocol)
  else
    raise "Unknown protocol descriptor: #{read_write}. Must be :READ, :WRITE, or :READ_WRITE."
  end
  @protocol_info << [protocol_class, protocol_args, read_write]
  protocol.interface = self
end

#connectObject

Connects the interface to its target(s). Must be implemented by a subclass.



157
158
159
# File 'lib/cosmos/interfaces/interface.rb', line 157

def connect
  (@read_protocols | @write_protocols).each {|protocol| protocol.connect_reset}
end

#connected?Boolean

Indicates if the interface is connected to its target(s) or not. Must be implemented by a subclass.

Returns:

  • (Boolean)


163
164
165
# File 'lib/cosmos/interfaces/interface.rb', line 163

def connected?
  raise "connected? not defined by Interface"
end

#convert_data_to_packet(data) ⇒ Packet

Called to convert the read data into a COSMOS Packet object

Parameters:

  • data (String)

    Raw packet data

Returns:

  • (Packet)

    COSMOS Packet with buffer filled with data



374
375
376
# File 'lib/cosmos/interfaces/interface.rb', line 374

def convert_data_to_packet(data)
  Packet.new(nil, nil, :BIG_ENDIAN, nil, data)
end

#convert_packet_to_data(packet) ⇒ Object

Called to convert a packet into the data to send

Parameters:

  • packet (Packet)

    Packet to extract data from

Returns:

  • data



382
383
384
# File 'lib/cosmos/interfaces/interface.rb', line 382

def convert_packet_to_data(packet)
  packet.buffer(true) # Copy buffer so logged command isn't modified
end

#copy_to(other_interface) ⇒ Object

Copy settings from this interface to another interface. All instance variables are copied except for thread, num_clients, read_queue_size, and write_queue_size since these are all specific to the operation of the interface rather than its instantiation.

Parameters:

  • other_interface (Interface)

    The other interface to copy to



334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
# File 'lib/cosmos/interfaces/interface.rb', line 334

def copy_to(other_interface)
  other_interface.name = self.name.clone
  other_interface.target_names = self.target_names.clone
  # The other interface has its own Thread
  other_interface.connect_on_startup = self.connect_on_startup
  other_interface.auto_reconnect = self.auto_reconnect
  other_interface.reconnect_delay = self.reconnect_delay
  other_interface.disable_disconnect = self.disable_disconnect
  other_interface.packet_log_writer_pairs = self.packet_log_writer_pairs.clone
  other_interface.routers = self.routers.clone
  other_interface.cmd_routers = self.cmd_routers.clone
  other_interface.read_count = self.read_count
  other_interface.write_count = self.write_count
  other_interface.bytes_read = self.bytes_read
  other_interface.bytes_written = self.bytes_written
  other_interface.raw_logger_pair = self.raw_logger_pair.clone if @raw_logger_pair
  # num_clients is per interface so don't copy
  # read_queue_size is the number of packets in the queue so don't copy
  # write_queue_size is the number of packets in the queue so don't copy
  other_interface.interfaces = self.interfaces.clone
  other_interface.options = self.options.clone
  other_interface.protocol_info = []
  self.protocol_info.each do |protocol_class, protocol_args, read_write|
    other_interface.add_protocol(protocol_class, protocol_args, read_write)
  end
  other_interface.override_tlm = nil
  other_interface.override_tlm = self.override_tlm.clone if self.override_tlm
end

#disconnectObject

Disconnects the interface from its target(s). Must be implemented by a subclass.



169
170
171
# File 'lib/cosmos/interfaces/interface.rb', line 169

def disconnect
  (@read_protocols | @write_protocols).each {|protocol| protocol.disconnect_reset}
end

#readPacket

Retrieves the next packet from the interface.

Returns:

  • (Packet)

    Packet constructed from the data. Packet will be unidentified (nil target and packet names)



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/cosmos/interfaces/interface.rb', line 184

def read
  raise "Interface not connected for read: #{@name}" unless connected? && read_allowed?

  first = true
  loop do
    # Protocols may have cached data for a packet, so initially just inject a blank string
    # Otherwise we can hold off outputing other packets where all the data has already
    # been received
    if !first or @read_protocols.length <= 0
      # Read data for a packet
      data = read_interface()
      return nil unless data
    else
      data = ''
      first = false
    end

    @read_protocols.each do |protocol|
      data = protocol.read_data(data)
      return nil if data == :DISCONNECT # Disconnect handled by thread
      break if data == :STOP
    end
    next if data == :STOP

    packet = convert_data_to_packet(data)

    # Potentially modify packet
    @read_protocols.each do |protocol|
      packet = protocol.read_packet(packet)
      return nil if packet == :DISCONNECT # Disconnect handled by thread
      break if packet == :STOP
    end
    next if packet == :STOP

    # Return packet
    @read_count += 1
    return packet
  end
rescue Exception => err
  Logger.instance.error("Error reading from interface : #{@name}")
  disconnect()
  raise err
end

#read_allowed?Boolean

Returns Whether reading is allowed.

Returns:

  • (Boolean)

    Whether reading is allowed



298
299
300
# File 'lib/cosmos/interfaces/interface.rb', line 298

def read_allowed?
  @read_allowed
end

#read_interfaceObject



173
174
175
# File 'lib/cosmos/interfaces/interface.rb', line 173

def read_interface
  raise "read_interface not defined by Interface"
end

#read_interface_base(data) ⇒ String

Called to read data and manipulate it until enough data is returned. The definition of ‘enough data’ changes depending on the protocol used which is why this method exists. This method is also used to perform operations on the data before it can be interpreted as packet data such as decryption. After this method is called the post_read_data method is called. Subclasses must implement this method.

Returns:

  • (String)

    Raw packet data



394
395
396
397
398
399
# File 'lib/cosmos/interfaces/interface.rb', line 394

def read_interface_base(data)
  @read_raw_data_time = Time.now
  @read_raw_data = data.clone
  @bytes_read += data.length
  @raw_logger_pair.read_logger.write(data) if @raw_logger_pair
end

#set_option(option_name, option_values) ⇒ Object

Set an interface or router specific option

Parameters:

  • option_name

    name of the option

  • option_values

    array of option values



366
367
368
# File 'lib/cosmos/interfaces/interface.rb', line 366

def set_option(option_name, option_values)
  @options[option_name.upcase] = option_values.clone
end

#start_raw_loggingObject

Start raw logging for this interface



313
314
315
# File 'lib/cosmos/interfaces/interface.rb', line 313

def start_raw_logging
  @raw_logger_pair.start if @raw_logger_pair
end

#stop_raw_loggingObject

Stop raw logging for this interface



318
319
320
# File 'lib/cosmos/interfaces/interface.rb', line 318

def stop_raw_logging
  @raw_logger_pair.stop if @raw_logger_pair
end

#write(packet) ⇒ Object

Method to send a packet on the interface.

Parameters:

  • packet (Packet)

    The Packet to send out the interface



230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
# File 'lib/cosmos/interfaces/interface.rb', line 230

def write(packet)
  raise "Interface not connected for write: #{@name}" unless connected? && write_allowed?
  _write do
    @write_count += 1

    # Potentially modify packet
    @write_protocols.each do |protocol|
      packet = protocol.write_packet(packet)
      if packet == :DISCONNECT
        disconnect()
        return
      end
      return if packet == :STOP
    end

    data = convert_packet_to_data(packet)

    # Potentially modify packet data
    @write_protocols.each do |protocol|
      data = protocol.write_data(data)
      if data == :DISCONNECT
        disconnect()
        return
      end
      return if data == :STOP
    end

    # Actually write out data if not handled by protocol
    write_interface(data)

    # Potentially block and wait for response
    @write_protocols.each do |protocol|
      packet, data = protocol.post_write_interface(packet, data)
      if packet == :DISCONNECT
        disconnect()
        return
      end
      return if packet == :STOP
    end
  end

  return nil
end

#write_allowed?Boolean

Returns Whether writing is allowed.

Returns:

  • (Boolean)

    Whether writing is allowed



303
304
305
# File 'lib/cosmos/interfaces/interface.rb', line 303

def write_allowed?
  @write_allowed
end

#write_interfaceObject



177
178
179
# File 'lib/cosmos/interfaces/interface.rb', line 177

def write_interface
  raise "write_interface not defined by Interface"
end

#write_interface_base(data) ⇒ String

Called to write data to the underlying interface. Subclasses must implement this method and call super to count the raw bytes and allow raw logging.

Parameters:

  • data (String)

    Raw packet data

Returns:

  • (String)

    The exact data written



407
408
409
410
411
412
# File 'lib/cosmos/interfaces/interface.rb', line 407

def write_interface_base(data)
  @written_raw_data_time = Time.now
  @written_raw_data = data.clone
  @bytes_written += data.length
  @raw_logger_pair.write_logger.write(data) if @raw_logger_pair
end

#write_raw(data) ⇒ Object

Writes preformatted data onto the interface. Malformed data may cause problems.

Parameters:

  • data (String)

    The raw data to send out the interface



277
278
279
280
281
282
# File 'lib/cosmos/interfaces/interface.rb', line 277

def write_raw(data)
  raise "Interface not connected for write_raw : #{@name}" unless connected? && write_raw_allowed?
  _write do
    write_interface(data)
  end
end

#write_raw_allowed?Boolean

Returns Whether writing raw data over the interface is allowed.

Returns:

  • (Boolean)

    Whether writing raw data over the interface is allowed



308
309
310
# File 'lib/cosmos/interfaces/interface.rb', line 308

def write_raw_allowed?
  @write_raw_allowed
end