/* * Copyright (C) 2014 Alfons Wirtz * website www.freerouting.net * * 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 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License at <http://www.gnu.org/licenses/> * for more details. * * InputDsnFile.java * * Created on 10. Mai 2004, 07:43 */ package designformats.specctra; import datastructures.IndentFileWriter; import board.BasicBoard; import board.TestLevel; /** * Class for reading and writing dsn-files. * * @author alfons */ public class DsnFile { public enum ReadResult { OK, OUTLINE_MISSING, ERROR } private DsnFile() { } /** * Creates a routing board from a Specctra dns file. * The parameters p_item_observers and p_item_id_no_generator are used, * in case the board is embedded into a host system. * Returns false, if an error occured. */ public static ReadResult read(java.io.InputStream p_input_stream, interactive.IBoardHandling p_board_handling, board.BoardObservers p_observers, datastructures.IdNoGenerator p_item_id_no_generator, TestLevel p_test_level) { Scanner scanner = new SpecctraFileScanner(p_input_stream); Object curr_token = null; for (int i = 0; i < 3; ++i) { try { curr_token = scanner.next_token(); } catch (java.io.IOException e) { System.out.println("DsnFile.read: IO error scanning file"); System.out.println(e); return ReadResult.ERROR; } boolean keyword_ok = true; if (i == 0) { keyword_ok = (curr_token == Keyword.OPEN_BRACKET); } else if (i == 1) { keyword_ok = (curr_token == Keyword.PCB_SCOPE); scanner.yybegin(SpecctraFileScanner.NAME); // to overread the name of the pcb for i = 2 } if (!keyword_ok) { System.out.println("DsnFile.read: specctra dsn file format expected"); return ReadResult.ERROR; } } ReadScopeParameter read_scope_par = new ReadScopeParameter(scanner, p_board_handling, p_observers, p_item_id_no_generator, p_test_level); boolean read_ok = Keyword.PCB_SCOPE.read_scope(read_scope_par); ReadResult result; if (read_ok) { result = ReadResult.OK; if (read_scope_par.autoroute_settings == null) { // look for power planes with incorrect layer type and adjust autoroute parameters adjust_plane_autoroute_settings(p_board_handling); } } else if (!read_scope_par.board_outline_ok) { result = ReadResult.OUTLINE_MISSING; } else { result = ReadResult.ERROR; } //tests.Validate.check("after reading dsn", read_scope_par.board_handling.get_routing_board()); return result; } /** * Sets contains_plane to true for nets with a conduction_area covering a * large part of a signal layer, if that layer does not contain any traces * This is useful in case the layer type was not set correctly to plane in the dsn-file. * Returns true, if something was changed. */ private static boolean adjust_plane_autoroute_settings(interactive.IBoardHandling p_board_handling) { BasicBoard routing_board = p_board_handling.get_routing_board(); board.LayerStructure board_layer_structure = routing_board.layer_structure; if (board_layer_structure.arr.length <= 2) { return false; } for (board.Layer curr_layer : board_layer_structure.arr) { if (!curr_layer.is_signal) { return false; } } boolean[] layer_contains_wires_arr = new boolean[board_layer_structure.arr.length]; boolean[] changed_layer_arr = new boolean[board_layer_structure.arr.length]; for (int i = 0; i < layer_contains_wires_arr.length; ++i) { layer_contains_wires_arr[i] = false; changed_layer_arr[i] = false; } java.util.Collection<board.ConductionArea> conduction_area_list = new java.util.LinkedList<board.ConductionArea>(); java.util.Collection<board.Item> item_list = routing_board.get_items(); for (board.Item curr_item : item_list) { if (curr_item instanceof board.Trace) { int curr_layer = ((board.Trace) curr_item).get_layer(); layer_contains_wires_arr[curr_layer] = true; } else if (curr_item instanceof board.ConductionArea) { conduction_area_list.add((board.ConductionArea) curr_item); } } boolean nothing_changed = true; board.BoardOutline board_outline = routing_board.get_outline(); double board_area = 0; for (int i = 0; i < board_outline.shape_count(); ++i) { geometry.planar.TileShape[] curr_piece_arr = board_outline.get_shape(i).split_to_convex(); if (curr_piece_arr != null) { for (geometry.planar.TileShape curr_piece : curr_piece_arr) { board_area += curr_piece.area(); } } } for (board.ConductionArea curr_conduction_area : conduction_area_list) { int layer_no = curr_conduction_area.get_layer(); if (layer_contains_wires_arr[layer_no]) { continue; } board.Layer curr_layer = routing_board.layer_structure.arr[layer_no]; if (!curr_layer.is_signal || layer_no == 0 || layer_no == board_layer_structure.arr.length - 1) { continue; } geometry.planar.TileShape[] convex_pieces = curr_conduction_area.get_area().split_to_convex(); double curr_area = 0; for (geometry.planar.TileShape curr_piece : convex_pieces) { curr_area += curr_piece.area(); } if (curr_area < 0.5 * board_area) { // skip conduction areas not covering most of the board continue; } for (int i = 0; i < curr_conduction_area.net_count(); ++i) { rules.Net curr_net = routing_board.rules.nets.get(curr_conduction_area.get_net_no(i)); curr_net.set_contains_plane(true); nothing_changed = false; } changed_layer_arr[layer_no] = true; if (curr_conduction_area.get_fixed_state().ordinal() < board.FixedState.USER_FIXED.ordinal()) { curr_conduction_area.set_fixed_state(board.FixedState.USER_FIXED); } } if (nothing_changed) { return false; } // Adjust the layer prefered directions in the autoroute settings. // and deactivate the changed layers. interactive.AutorouteSettings autoroute_settings = p_board_handling.get_settings().autoroute_settings; int layer_count = routing_board.get_layer_count(); boolean curr_preferred_direction_is_horizontal = autoroute_settings.get_preferred_direction_is_horizontal(0); for (int i = 0; i < layer_count; ++i) { if (changed_layer_arr[i]) { autoroute_settings.set_layer_active(i, false); } else if (autoroute_settings.get_layer_active(i)) { autoroute_settings.set_preferred_direction_is_horizontal(i, curr_preferred_direction_is_horizontal); curr_preferred_direction_is_horizontal = !curr_preferred_direction_is_horizontal; } } return true; } /** * Writes p_board to a text file in the Specctra dsn format. * Returns false, if the write failed. * If p_compat_mode is true, only standard speecctra dsn scopes are written, so that any * host system with an specctra interface can read them. */ public static boolean write(interactive.BoardHandling p_board_handling, java.io.OutputStream p_file, String p_design_name, boolean p_compat_mode) { //tests.Validate.check("before writing dsn", p_board); IndentFileWriter output_file = new IndentFileWriter(p_file); if (output_file == null) { System.out.println("unable to write dsn file"); return false; } try { write_pcb_scope(p_board_handling, output_file, p_design_name, p_compat_mode); } catch (java.io.IOException e) { System.out.println("unable to write dsn file"); return false; } try { output_file.close(); } catch (java.io.IOException e) { System.out.println("unable to close dsn file"); return false; } return true; } private static void write_pcb_scope(interactive.BoardHandling p_board_handling, IndentFileWriter p_file, String p_design_name, boolean p_compat_mode) throws java.io.IOException { BasicBoard routing_board = p_board_handling.get_routing_board(); WriteScopeParameter write_scope_parameter = new WriteScopeParameter(routing_board, p_board_handling.settings.autoroute_settings, p_file, routing_board.communication.specctra_parser_info.string_quote, routing_board.communication.coordinate_transform, p_compat_mode); p_file.start_scope(); p_file.write("PCB "); write_scope_parameter.identifier_type.write(p_design_name, p_file); Parser.write_scope(write_scope_parameter.file, write_scope_parameter.board.communication.specctra_parser_info, write_scope_parameter.identifier_type, false); Resolution.write_scope(p_file, routing_board.communication); Structure.write_scope(write_scope_parameter); Placement.write_scope(write_scope_parameter); Library.write_scope(write_scope_parameter); PartLibrary.write_scope(write_scope_parameter); Network.write_scope(write_scope_parameter); Wiring.write_scope(write_scope_parameter); p_file.end_scope(); } static boolean read_on_off_scope(Scanner p_scanner) { try { Object next_token = p_scanner.next_token(); boolean result = false; if (next_token == Keyword.ON) { result = true; } else if (next_token != Keyword.OFF) { System.out.println("DsnFile.read_boolean: Keyword.OFF expected"); } ScopeKeyword.skip_scope(p_scanner); return result; } catch (java.io.IOException e) { System.out.println("DsnFile.read_boolean: IO error scanning file"); return false; } } static int read_integer_scope(Scanner p_scanner) { try { int value; Object next_token = p_scanner.next_token(); if (next_token instanceof Integer) { value = ((Integer) next_token).intValue(); } else { System.out.println("DsnFile.read_integer_scope: number expected"); return 0; } next_token = p_scanner.next_token(); if (next_token != Keyword.CLOSED_BRACKET) { System.out.println("DsnFile.read_integer_scope: closing bracket expected"); return 0; } return value; } catch (java.io.IOException e) { System.out.println("DsnFile.read_integer_scope: IO error scanning file"); return 0; } } static double read_float_scope(Scanner p_scanner) { try { double value; Object next_token = p_scanner.next_token(); if (next_token instanceof Double) { value = ((Double) next_token).doubleValue(); } else if (next_token instanceof Integer) { value = ((Integer) next_token).intValue(); } else { System.out.println("DsnFile.read_float_scope: number expected"); return 0; } next_token = p_scanner.next_token(); if (next_token != Keyword.CLOSED_BRACKET) { System.out.println("DsnFile.read_float_scope: closing bracket expected"); return 0; } return value; } catch (java.io.IOException e) { System.out.println("DsnFile.read_float_scope: IO error scanning file"); return 0; } } public static String read_string_scope(Scanner p_scanner) { try { p_scanner.yybegin(SpecctraFileScanner.NAME); Object next_token = p_scanner.next_token(); if (!(next_token instanceof String)) { System.out.println("DsnFile:read_string_scope: String expected"); return null; } String result = (String) next_token; next_token = p_scanner.next_token(); if (next_token != Keyword.CLOSED_BRACKET) { System.out.println("DsnFile.read_string_scope: closing bracket expected"); } return result; } catch (java.io.IOException e) { System.out.println("DsnFile.read_string_scope: IO error scanning file"); return null; } } public static java.util.Collection<String> read_string_list_scope(Scanner p_scanner) { java.util.Collection<String> result = new java.util.LinkedList<String>(); try { for (;;) { p_scanner.yybegin(SpecctraFileScanner.NAME); Object next_token = p_scanner.next_token(); if (next_token == Keyword.CLOSED_BRACKET) { break; } if (!(next_token instanceof String)) { System.out.println("DsnFileread_string_list_scope: string expected"); return null; } result.add((String) next_token); } } catch (java.io.IOException e) { System.out.println("DsnFile.read_string_list_scope: IO error scanning file"); } return result; } static final String CLASS_CLEARANCE_SEPARATOR = "-"; }