summaryrefslogtreecommitdiff
path: root/Data/Stdf/Types.hs
blob: 1e8fdaf3ca34e8093f1a4bbc14df7bcaf7deaf60 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
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
227
228
229
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
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
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
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456

{-# LANGUAGE DeriveGeneric #-}

module Data.Stdf.Types where

import Data.Word
import Data.Int
import Foreign.C.Types
import Data.Text.Lazy
import GHC.Generics hiding (U1, C1)
import Data.Aeson
import Data.Aeson.Types
import Data.Time.Clock

-- Time is local unix time. Shouldn't they put the time zone in the file
-- in order for this to have any meaning? What if the data isn't being parsed
-- in the same time zone as it was generated? It will be as if the tester
-- was transported through time and space to wherever I am. I think I'll
-- just leave it alone so times can be Word32 representing Unix time

type U1 = Word8  -- unsigned 1 byte
type U2 = Word16 -- unsigned 2 bytes
type U4 = Word32 -- unsigned 4 bytes
type I1 = Int8
type I2 = Int16
type I4 = Int32
type R4 = Float -- CFloat
type R8 = Double -- CDouble
type C1 = Char

jsonOptions = defaultOptions {
      allNullaryToStringTag = False
    , omitNothingFields = True
    , sumEncoding = ObjectWithSingleField
    }

flagOptions = defaultOptions

instance ToJSON Milliseconds where
    toJSON = genericToJSON jsonOptions
instance ToJSON Minutes where
    toJSON = genericToJSON jsonOptions
instance ToJSON Rec where
    toJSON = genericToJSON jsonOptions
instance ToJSON PartFlag where
    toJSON = genericToJSON jsonOptions
instance ToJSON GdrField where
    toJSON = genericToJSON jsonOptions
instance ToJSON TestType where
    toJSON = genericToJSON jsonOptions
instance ToJSON WaferUnits where
    toJSON = genericToJSON jsonOptions
instance ToJSON Direction where
    toJSON = genericToJSON jsonOptions
instance ToJSON OptionalInfo where
    toJSON = genericToJSON jsonOptions
instance ToJSON GroupMode where
    toJSON = genericToJSON jsonOptions
instance ToJSON Radix where
    toJSON = genericToJSON jsonOptions
instance ToJSON TestFlag where
    toJSON = genericToJSON flagOptions
instance ToJSON PassFailBin where
    toJSON = genericToJSON jsonOptions
instance ToJSON ParametricFlag where
    toJSON = genericToJSON flagOptions

data BinRec = BinRec 
    { header :: Header
    , rec :: Rec } deriving (Generic, Show)

data Header = Header
    { len :: !Word16
    , typ :: !Word8
    , sub :: !Word8
    } deriving (Generic, Show)

type Stdf = [Rec]

data Milliseconds = Milliseconds { ms :: !U4 }
    deriving (Generic, Show)

data Minutes = Minutes { minutes :: !U2 }
    deriving (Generic, Show)

-- The mother of all datatypes
data Rec= Raw { raw :: Text } -- base64 TODO: URL encoding or maybe don't bother. what's this good for?
        | Far { cpuType  :: !U1
              , stdfVersion  :: !U1 }
        | Atr { modificationTime :: Maybe UTCTime
              , commandLine :: Maybe Text }
        | Mir { setupTime :: Maybe UTCTime
              , startTime :: Maybe UTCTime
              , station :: !U1
              , modeCode :: Maybe C1 -- TODO: MODE_COD record
              , retestCode :: Maybe C1 -- TODO: RTST_COD record
              , protectionCode :: Maybe C1 -- ' '
              , burninTime :: Maybe Minutes -- 65,535
              , commandCode :: Maybe C1 -- ' '
              , lotId :: Text
              , partType :: Text
              , nodeName :: Text
              , testerType :: Text
              , jobName :: Text
              , jobRevision :: Maybe Text
              , subLotId :: Maybe Text
              , operatorName :: Maybe Text
              , execType :: Maybe Text
              , execVersion :: Maybe Text
              , testCode :: Maybe Text
              , testTemperature :: Maybe Text
              , userText :: Maybe Text
              , auxFile :: Maybe Text
              , packageType :: Maybe Text
              , familyId :: Maybe Text
              , dateCode :: Maybe Text
              , facilityId :: Maybe Text
              , floorId :: Maybe Text
              , processId :: Maybe Text
              , operationFreq :: Maybe Text
              , specName :: Maybe Text
              , specVersion :: Maybe Text
              , flowId :: Maybe Text
              , setupId :: Maybe Text
              , designRev :: Maybe Text
              , engineeringLotId :: Maybe Text
              , romCodeId :: Maybe Text
              , testerSerialNum :: Maybe Text
              , supervisorName :: Maybe Text }
        | Mrr { finishTime :: Maybe UTCTime
              , lotDisposition :: Maybe C1
              , userDescription :: Maybe Text
              , execDescription :: Maybe Text }
        | Pcr { headId :: !U1
              , siteId :: !U1
              , partCount :: !U4
              , retestCount :: Maybe U4
              , abortCount :: Maybe U4
              , goodCount :: Maybe U4
              , functionalCount :: Maybe U4 }
        | Hbr { headId :: !U1
              , siteId :: !U1
              , bin :: !U2
              , binCount :: !U4
              , passFailBin :: PassFailBin
              , name :: Maybe Text }
        | Sbr { headId :: !U1
              , siteId :: !U1
              , bin :: !U2
              , binCount :: !U4
              , passFail :: PassFailBin
              , name :: Maybe Text }
        | Pmr { index :: !U2 -- Maybe rather than index reference by name
              , channelType :: Maybe U2
              , channelName :: Maybe Text
              , physicalName :: Maybe Text
              , logicalName :: Maybe Text
              , headId :: !U1
              , siteId :: !U1 }
        | Pgr { index :: !U2
              , name :: Maybe Text
              , pinIndecies :: [U2] } -- list of pins instead of refering to indecies
        -- Parsing: 
        -- Empty arrays (or empty members of arrays) can be omitted 
        -- if they occur at the end of the record.
        | Plr { 
              -- Instead of Maybe [] opt for empty [Maybe]
                indecies :: [U2]
              , groupModes :: [GroupMode]
              , groupRadixes :: [Radix]
              -- Should really just use a string for state characters
              -- instead of Left/Right but failed since I don't have example PLR
              -- , programStateChars :: [Text] -- combine CharR and CharL at parse?
              -- , returnStateChars :: [Text] }
              , programStateCharsRight :: [Maybe Text]
              , returnStateCharsRight :: [Maybe Text]
              , programStateCharsLeft :: [Maybe Text]
              , returnStateCharsLeft :: [Maybe Text] }
        | Rdr { retestBins :: [U2] }
        | Sdr { headId :: !U1
              , siteGroup :: !U1
              , sites :: [U1]
              , handlerType :: Maybe Text
              , handlerId :: Maybe Text
              , probeCardType :: Maybe Text
              , probeCardId :: Maybe Text
              , loadBoardType :: Maybe Text
              , loadBoardId :: Maybe Text
              , dibType :: Maybe Text
              , dibId :: Maybe Text
              , cableType :: Maybe Text
              , cableId :: Maybe Text
              , contactorType :: Maybe Text
              , contactorId :: Maybe Text
              , laserType :: Maybe Text
              , laserId :: Maybe Text
              , extraType :: Maybe Text
              , extraId :: Maybe Text }
        | Wir { headId :: !U1
              , siteGroup :: !U1 -- 255 -> Nothing -- feature removed
              , startTime :: Maybe UTCTime
              , waferId :: Maybe Text }
        | Wrr { headId :: !U1
              , siteGroup :: !U1  -- 255 means Nothing
              , finishTime :: Maybe UTCTime
              , partCount :: !U4
              , retestCount :: Maybe U4 -- 4,294,967,295 -> Nothing
              , abortCount :: Maybe U4 -- 4,294,967,295 -> Nothing
              , goodCount :: Maybe U4 -- 4,294,967,295 -> Nothing
              , functionalCount :: Maybe U4 -- 4,294,967,295 -> Nothing
              , waferId :: Maybe Text -- length 0 -> Nothing
              , fabWaferId :: Maybe Text -- length 0 -> Nothing
              , waferFrameId :: Maybe Text -- length 0 -> Nothing
              , waferMaskId :: Maybe Text -- length 0 -> Nothing
              , userDescription :: Maybe Text -- length 0 -> Nothing
              , execDescription :: Maybe Text }
        | Wcr { waferSize :: Maybe R4 -- 0 -> Nothing
              , dieHeight :: Maybe R4
              , dieWidth :: Maybe R4
              , waferUnits :: Maybe WaferUnits
              , waferFlat :: Maybe Direction
              , centerX :: Maybe I2
              , centerY :: Maybe I2
              , positiveXdirection :: Maybe Direction
              , positiveYdirection :: Maybe Direction }
        | Pir { headId :: !U1
              , siteId :: !U1 }
        | Prr { headId  :: !U1
                , siteId  :: !U1
                , partFlag  :: !PartFlag
                , numTestsExecuted  :: !U2
                , hardBin  :: !U2
                , softBin  :: Maybe U2
                , xCoord   :: Maybe I2
                , yCoord   :: Maybe I2
                , testTime :: Maybe Milliseconds -- TODO: type milliseconds like minutes or call this field milliseconds
                , partID   :: Maybe Text
                , partTxt  :: Maybe Text
                , partFix  :: Maybe Text }
        | Tsr { headId :: !U1
              , siteId :: !U1
              , testType :: Maybe TestType
              , testId :: !U4
              , execCount :: Maybe U4
              , failCount :: Maybe U4
              , alarmCount :: Maybe U4
              , testName :: Maybe Text
              , sequencerName :: Maybe Text
              , testLabel :: Maybe Text
              -- , optionalFlags :: !U1 -- parsing optional if last field in record
              , testTimeAverage :: Maybe R4 -- optional fields based on optionalFlags TODO: name this field averageSeconds or make a Seconds type
              , valueMin :: Maybe R4 -- may make these another record type
              , valueMax :: Maybe R4
              , valueSum :: Maybe R4
              , valueSumOfSquares :: Maybe R4 }
        | Ptr { testId :: !U4
              , headId :: !U1
              , siteId :: !U1
              , testFlags :: [TestFlag] -- B1 bitfield further parsing bits
              , parametricFlags :: [ParametricFlag] -- B1 bitfield further parsing bits
              , result :: Maybe R4
              , testText :: Maybe Text
              -- , alarmId :: Maybe Text -> optionalInfo
              , info :: [OptionalInfo] } -- TODO: better name -- Maybe so empty ones don't print in Json
        | Mpr { testId :: !U4
              , headId :: !U1
              , siteId :: !U1
              , testFlags :: [TestFlag]
              , parametricFlags :: [ParametricFlag]
              -- j , stateCount :: U2
              -- k , resultCount :: U2
              , states :: [U1] -- Nibbles! array of states? j states
              , results :: [R4] -- k results
              , testText :: Maybe Text
              , info :: [OptionalInfo] }
              -- , alarmId :: Maybe Text
              -- -- , OPT_FLG B1 optional stuff to parse
              -- , resultExp :: Maybe I1  -- TODO: put mostly in OptionalInfo
              -- , lowLimitExp :: Maybe I1
              -- , highLimitExp :: Maybe I1
              -- , lowLimit :: Maybe R4
              -- , highLimit :: Maybe R4
              -- , startingInput :: Maybe R4
              -- , incrementInput :: Maybe R4
              -- , returnPinIndecies :: Maybe [U2] -- k indecies
              -- , units :: Maybe Text
              -- , unitsInputCondition  :: Maybe Text
              -- , printfResultFmt :: Maybe Text
              -- , printfLowLimitFmt :: Maybe Text
              -- , printfHighLimitFmt :: Maybe Text
              -- , lowSpecLimit :: Maybe R4
              -- , highSpecLimit :: Maybe R4 }
        | Ftr { testId :: !U4
              , headId :: !U1
              , siteId :: !U1
              , testFlags :: [TestFlag]
              , info :: [OptionalInfo]
              -- -- , optFlg :: !U1 -- 8 bit packed binary -- record may have ended by here
              -- , cycleCount :: Maybe U4    -- To Optional Info
              -- , relativeVectorAddr :: Maybe U4
              -- , numFailingPins :: Maybe U4
              -- , xLogicalFailureAddr :: Maybe I4
              -- , yLogicalFailureAddr :: Maybe I4
              -- , offsetFromVector :: Maybe I2
              -- -- j U2
              -- -- k U2
              -- , pinIndecies :: Maybe [U2] -- j x U2
              -- , returnedStates :: Maybe [U1] -- j NIBBLES!
              -- , pgmStateIndecies :: Maybe [U2] -- k x U2
              -- , pgmStates :: Maybe [U1] -- k NIBBLES!
              -- , failPin :: Maybe [U1] -- bitfield!
              -- , vector :: Maybe Text
              -- , timeSet :: Maybe Text
              -- , opCode :: Maybe Text
              -- , label :: Maybe Text
              -- , alarmId :: Maybe Text
              -- , programText :: Maybe Text
              -- , resultText :: Maybe Text
              -- , patternGen :: Maybe U1  -- 255
              -- , enabledPins :: Maybe [U1] -- bitfield!
              } -- TODO: this is a long silly record. there's a bunch more things
        | Bps { sequencerName :: Maybe Text }  -- Begin Program Secion
        | Eps -- End Program Section: no payload
        | Gdr [GdrField]
        | Dtr { textDat :: Text }
          deriving (Generic, Show)

data GroupMode = UnknownGroupMode
               | Normal
               | SameCycleIO
               | SameCycleMidband
               | SameCycleValid
               | SameCycleWindowSustain
               | DualDrive
               | DualDriveMidband
               | DualDriveValid
               | DualDriveWindowSustain
               | OtherGroupMode U2
               deriving (Generic, Show)

data Radix = DefaultRadix
           | Binary
           | Octal
           | Decimal
           | Hexadecimal
           | Symbolic
           | OtherRadix U1
           deriving (Generic, Show)

data TestFlag = Alarm       -- bit 0
              | Invalid     -- bit 1
              | Unreliable  -- bit 2
              | Timeout     -- bit 3
              | NotExecuted -- bit 4
              | Aborted     -- bit 5
              | InValid     -- bit 6
              | Pass        -- bit 7 == 0
              | Fail        -- bit 7
              deriving (Generic, Show, Eq, Enum)

data PassFailBin = PassBin | FailBin | UnknownBin | OtherBin Char
    deriving (Generic, Show)

data ParametricFlag = ScaleError          -- bit 0
                    | DriftError          -- bit 1
                    | Oscillation         -- bit 2
                    | FailHighLimit       -- bit 3
                    | FailLowLimit        -- bit 4
                    | PassAlternateLimits -- bit 5
                    | PassOnEqLowLimit    -- bit 6
                    | PassOnEqHighLimit   -- bit 7
                    -- bits 6 & 7 seem stupid
                    deriving (Generic, Show, Eq, Enum)

-- TODO: Another pass at scaling flags
-- Maybe better as sum type
data OptionalInfo   = Units Text
                    | LowSpecLimit Float
                    | HighSpecLimit Float
                    | LowSpecLimitStr Text
                    | HighSpecLimitStr Text
                    | AlarmId Text
                    | LowLimit Float
                    | HighLimit Float
                    | LowLimitStr Text
                    | HighLimitStr Text
                    | ResultStr Text
                    | StartingInput Float
                    | StartingInputUnits Text
                    | IncrementInput Float
                    -- change to a map of pinName -> state
                    | ReturnPinIndecies [U2]  -- k
                    | CycleCount U4
                    | RepeatCount U4
                    | RelativeVectorAddr U4
                    | NumFailingPins U4
                    | XLogicalFailureAddr I4
                    | YLogicalFailureAddr I4
                    | OffsetFromVector I2
                    | PinIndecies [U2] -- j x U2 -- redundant with ReturnPinIndecies?
                    | ReturnedStates [U1] -- j NIBBLES!
                    | PgmStateIndecies [U2] -- k x U2 -> Parse pin states?
                    | PgmStates [U1] -- k NIBBLES! -> String
                    | FailPin [U1] -- bitfield! -> [PinName]
                    | VectorName Text
                    | TimeSet Text
                    | OpCode Text
                    | Label Text
                    | ProgramText Text
                    | ResultText Text
                    | PatternGen U1  -- 255
                    | EnabledPins [U1] -- bitfield!
                    deriving (Generic, Show)

data TestType = Parametric
              | Functional
              | MultiResultParametric
              | UnknownTestType
              | OtherTestType C1
              deriving (Generic, Show)

data WaferUnits = Inches
                | Centimeters
                | Millimeters
                | Mils
                | OtherUnits U1
                deriving (Generic, Show)

data Direction = Up
               | Down
               | Left
               | Right
               | OtherDirection C1
               deriving (Generic, Show)

data GdrField = GPad -- discard
              | GU1 !U1
              | GU2 !U2
              | GU4 !U4
              | GI1 !I1
              | GI2 !I2
              | GI4 !I4
              | GFloat Float -- parse as CFloat
              | GDouble Double -- parse as CDouble
              | GStr Text
              | GBytes [U1] -- encoded ByteStr
              | GData [U1] -- 2byte length + encoded ByteStr
              | GNibble !U1 -- a nibble? are you fucking kidding me?
              deriving (Generic, Show)

data PartFlag = PartFlag { supersedesPartId :: Bool -- 1 bit
                       , supersedesXY :: Bool -- 1 bit
                       , abnormalEnd :: Bool
                       , failed :: Bool
                       , noPassFailInfo :: Bool }
                       deriving (Generic, Show)