001package jmri.jmrix.loconet.sdf;
002
003import jmri.util.StringUtil;
004import org.slf4j.Logger;
005import org.slf4j.LoggerFactory;
006
007/**
008 * Implement the LOAD_MODIFIER macro from the Digitrax sound definition language
009 *
010 * Arg1: Upper 4 bits - math modifiers FMATH_LODE et al Arg2: Arg3:
011 *
012 *
013 * @author Bob Jacobsen Copyright (C) 2007
014 */
015public class LoadModifier extends SdfMacro {
016
017    public LoadModifier(int byte0, int arg1, int arg2, int arg3) {
018        this.modType = byte0 & 0x0F;
019        this.byte0 = byte0;
020        this.arg1 = arg1;
021        this.arg2 = arg2;
022        this.arg3 = arg3;
023    }
024
025    @Override
026    public String name() {
027        return "LOAD_MODIFIER"; // NOI18N
028    }
029
030    int byte0;
031    int modType;
032    int arg1, arg2, arg3;
033
034    @Override
035    public int length() {
036        return 4;
037    }
038
039    static public SdfMacro match(SdfBuffer buff) {
040        // course match
041        if ((buff.getAtIndex() & 0xF0) != 0xE0) {
042            return null;
043        }
044        int byte1 = buff.getAtIndexAndInc() & 0xFF;
045        int byte2 = buff.getAtIndexAndInc() & 0xFF;
046        int byte3 = buff.getAtIndexAndInc() & 0xFF;
047        int byte4 = buff.getAtIndexAndInc() & 0xFF;
048        return new LoadModifier(byte1, byte2, byte3, byte4);
049    }
050
051    String modTypeVal() {
052        return jmri.util.StringUtil.getNameFromState(modType, modControlCodes, modControlNames);
053    }
054
055    /**
056     * Format the three bytes as simple numbers, for lack of anything better
057     * right now
058     * @return 3 digit string
059     */
060    String argVal() {
061        String arg1Val = "" + arg1;
062        String arg2Val = "" + arg2;
063        String arg3Val = "" + arg3;
064        return arg1Val + "," + arg2Val + "," + arg3Val;
065    }
066
067    /**
068     * Store into a buffer.
069     */
070    @Override
071    public void loadByteArray(SdfBuffer buffer) {
072        // data
073        buffer.setAtIndexAndInc(byte0);
074        buffer.setAtIndexAndInc(arg1);
075        buffer.setAtIndexAndInc(arg2);
076        buffer.setAtIndexAndInc(arg3);
077
078        // store children
079        super.loadByteArray(buffer);
080    }
081
082    @Override
083    public String toString() {
084        return "Set Modifier " + modTypeVal() + '\n'; // NOI18N
085    }
086
087    @Override
088    public String oneInstructionString() {
089        String args;
090        String arg1Val;
091        String arg2Val;
092        String arg3Val;
093        String temp1, temp2;
094
095        switch (modType) {
096            case MTYPE_TIME:
097                args = argVal();
098                return name() + ' ' + modTypeVal() + "," + args + '\n';
099
100            case MTYPE_GAIN:
101                // arg1 is IMMED_GAIN_MODIFY or ANALOG_GAIN_MODIFY
102                // plus possible 5 bit modifier
103                if ((arg1 & 0xE0) == IMMED_GAIN_MODIFY) {
104                    if (arg1 == IMMED_GAIN_MODIFY) {
105                        arg1Val = "IMMED_GAIN_MODIFY"; // NOI18N
106                    } else {
107                        arg1Val = "IMMED_GAIN_MODIFY+0x" + StringUtil.twoHexFromInt(arg1 & 0x1f); // NOI18N
108                    }
109                } else if ((arg1 & 0xE0) == ANALOG_GAIN_MODIFY) {
110                    if (arg1 == ANALOG_GAIN_MODIFY) {
111                        arg1Val = "ANALOG_GAIN_MODIFY"; // NOI18N
112                    } else {
113                        arg1Val = "ANALOG_GAIN_MODIFY+" // NOI18N
114                                + StringUtil.getNameFromState(arg1 & 0x1f, workRegCodes, workRegNames);
115                    }
116                } else {
117                    arg1Val = StringUtil.twoHexFromInt(arg1);
118                }
119                arg2Val = StringUtil.getNameFromState(arg2, fixedCVCodes, fixedCVNames);
120                if (arg2Val == null) {
121                    arg2Val = "0x" + StringUtil.twoHexFromInt(arg2); // NOI18N
122                }
123                arg3Val = decodeFlags(arg3, arg3ModCodes, arg3ModMasks, arg3ModNames);
124                if (arg3Val == null) {
125                    arg3Val = "0x" + StringUtil.twoHexFromInt(arg3); // NOI18N
126                }
127                return name() + ' ' + modTypeVal() + "," + arg1Val + "," + arg2Val + "," + arg3Val + '\n'; // NOI18N
128
129            case MTYPE_PITCH:
130                // arg1 is CV_PITCH_MODIFY or ANALOG_PITCH_MODIFY
131                // plus possible 5 bit modifier
132                if ((arg1 & 0xE0) == CV_PITCH_MODIFY) {
133                    if (arg1 == CV_PITCH_MODIFY) {
134                        arg1Val = "CV_PITCH_MODIFY"; // NOI18N
135                    } else {
136                        arg1Val = "CV_PITCH_MODIFY+0x" + StringUtil.twoHexFromInt(arg1 & 0x1f); // NOI18N
137                    }
138                } else if ((arg1 & 0xE0) == ANALOG_PITCH_MODIFY) {
139                    if (arg1 == ANALOG_PITCH_MODIFY) {
140                        arg1Val = "ANALOG_PITCH_MODIFY"; // NOI18N
141                    } else {
142                        arg1Val = "ANALOG_PITCH_MODIFY+" // NOI18N
143                                + StringUtil.getNameFromState(arg1 & 0x1f, workRegCodes, workRegNames);
144                    }
145                } else {
146                    arg1Val = StringUtil.twoHexFromInt(arg1);
147                }
148                arg2Val = StringUtil.getNameFromState(arg2, maxPCodes, maxPNames);
149                if (arg2Val == null) {
150                    arg2Val = "0x" + StringUtil.twoHexFromInt(arg2); // NOI18N
151                }
152                arg3Val = StringUtil.getNameFromState(arg3, ditherPCodes, ditherPNames);
153                if (arg3Val == null) {
154                    arg3Val = "0x" + StringUtil.twoHexFromInt(arg3); // NOI18N
155                }
156                return name() + ' ' + modTypeVal() + "," + arg1Val + "," + arg2Val + "," + arg3Val + '\n';
157
158            case MTYPE_BLEND:
159                arg1Val = decodeFlags(arg1, blendArg1Codes, blendArg1Masks, blendArg1Names);
160
161                arg2Val = StringUtil.getNameFromState(arg2, blendArg2Codes, blendArg2Names);
162                if (arg2Val == null) {
163                    arg2Val = "0x" + StringUtil.twoHexFromInt(arg2); // NOI18N
164                }
165
166                arg3Val = StringUtil.getNameFromState(arg3, blendArg3Codes, blendArg3Names);
167                if (arg3Val == null) {
168                    arg3Val = "0x" + StringUtil.twoHexFromInt(arg3); // NOI18N
169                }
170
171                return name() + ' ' + modTypeVal() + "," + arg1Val + "," + arg2Val + "," + arg3Val + '\n';
172
173            case MTYPE_SCATTER:
174                arg1Val = StringUtil.getNameFromState(arg1 & 0x38, scatCommandCodes, scatCommandNames)
175                        + "+" + StringUtil.getNameFromState(arg1 & 0x03, scatChannelCodes, scatChannelNames);
176
177                arg2Val = StringUtil.getNameFromState(arg2, fixedCVCodes, fixedCVNames);
178                if (arg2Val == null) {
179                    arg2Val = "0x" + StringUtil.twoHexFromInt(arg2); // NOI18N
180                }
181
182                arg3Val = StringUtil.getNameFromState(arg3, sintenCodes, sintenNames);
183                if (arg3Val == null) {
184                    arg3Val = "0x" + StringUtil.twoHexFromInt(arg3); // NOI18N
185                }
186
187                return name() + ' ' + modTypeVal() + "," + arg1Val + "," + arg2Val + "," + arg3Val + '\n';
188
189            case MTYPE_SNDCV:
190                arg1Val = StringUtil.getNameFromState(arg1, fixedCVCodes, fixedCVNames);
191                if (arg1Val == null) {
192                    arg1Val = "0x" + StringUtil.twoHexFromInt(arg1); // NOI18N
193                }
194                arg2Val = "" + arg2;
195                arg3Val = "" + arg3;
196                return name() + ' ' + modTypeVal() + "," + arg1Val + "," + arg2Val + "," + arg3Val + '\n';
197
198            case MTYPE_WORK_IMMED:
199                // math operations w immediate operands
200                temp1 = StringUtil.getNameFromState(arg1 & 0xE0, arg1ModCodes, arg1ModNames);
201                temp2 = StringUtil.getNameFromState(arg1 & 0x1F, workRegCodes, workRegNames);
202                if (temp1 != null && temp2 != null) {
203                    arg1Val = temp1 + "+" + temp2;
204                } else if (temp1 != null && temp2 == null) {
205                    arg1Val = temp1;
206                } else if (temp1 == null && temp2 != null) {
207                    arg1Val = temp2;
208                } else {
209                    arg1Val = "0"; // an odd error, actually
210                }
211                arg2Val = StringUtil.getNameFromState(arg2, maxPCodes, maxPNames);
212                if (arg2Val == null) {
213                    arg2Val = "0x" + StringUtil.twoHexFromInt(arg2); // NOI18N
214                }
215
216                // occasionally see MERGE_ALL_MASK in arg3, but that's zero
217                arg3Val = "" + arg3;
218
219                // special cases
220                //   status bit register
221                if ((arg1 & 0x1F) == WORK_STATUS_BITS) {
222                    arg2Val = decodeFlags(arg2, workStatusBitCodes, workStatusBitCodes, workStatusBitNames);
223                }
224                if ((arg1 & 0x1F) == WORK_GLBL_GAIN && arg2 == DEFAULT_GLBL_GAIN) {
225                    arg2Val = "DEFAULT_GLBL_GAIN"; // NOI18N
226                }
227                return name() + ' ' + modTypeVal() + "," + arg1Val + "," + arg2Val + "," + arg3Val + '\n';
228
229            case MTYPE_WORK_INDIRECT:
230                // math operations from one reg to another
231                temp1 = StringUtil.getNameFromState(arg1 & 0xE0, arg1ModCodes, arg1ModNames);
232                temp2 = StringUtil.getNameFromState(arg1 & 0x1F, workRegCodes, workRegNames);
233                if (temp1 != null && temp2 != null) {
234                    arg1Val = temp1 + "+" + temp2;
235                } else if (temp1 != null && temp2 == null) {
236                    arg1Val = temp1;
237                } else if (temp1 == null && temp2 != null) {
238                    arg1Val = temp2;
239                } else {
240                    arg1Val = "0"; // an odd error, actually // NOI18N
241                }
242                arg2Val = StringUtil.getNameFromState(arg2 & 0x1F, workRegCodes, workRegNames);
243                if (arg2Val == null) {
244                    arg2Val = "0x" + StringUtil.twoHexFromInt(arg2); // NOI18N
245                }
246
247                // occasionally see MERGE_ALL_MASK in arg3, but that's zero
248                arg3Val = "" + arg3;
249
250                return name() + ' ' + modTypeVal() + "," + arg1Val + "," + arg2Val + "," + arg3Val + '\n'; // NOI18N
251            default:
252                log.warn("Unhandled modifyer type code: {}", modType);
253                break;
254        }
255        return "<could not parse, should not happen>"; // NOI18N
256    }
257
258    @Override
259    public String allInstructionString(String indent) {
260        return indent + oneInstructionString();
261    }
262    
263    private final static Logger log = LoggerFactory.getLogger(LoadModifier.class);
264}