2

私は F# を初めて使用するので、この問題を解決するために助けが必要です。

シリアル ポートから来て、F# のシーケンスとして表されるバイト ストリームがあります。ストリームはフレームで構成され、それぞれが 0xFE で始まり 0xFF で終わります。バイトは連続して送信され、同期のために 0xFE までいくつかのバイトをスキップする必要があります。ただし、ストリームが破損している可能性があり、0xFE または 0xFF が欠落している可能性があります。

シリアルポートからの入力を反復する関数があります。関数のコードは次のとおりです。

let getFrame s =
    let r = s |> Seq.skipWhile (fun x->x<>0xFEuy) 
              |> Seq.takeWhile (fun x->x<>0xFFuy)
    if Seq.isEmpty r then r else Seq.skip 1 r

このコードを書き直して、0xFE までバイトをスキップするか、特定のバイト数をスキップし、0xFE が発生しない場合は機能的にエラーを返すようにするにはどうすればよいですか?

0xFF までフレーム バイトを取得する場合も同様です。

4

2 に答える 2

2

Option<'T>関数の結果としてタイプを使用できます。Some xこれは、一部のフレームが入力シーケンスからキャプチャされNone、フレーム データが見つからなかったことを意味します。

let getFrame s =
    let r = s |> Seq.skipWhile ((<>) 0xFEuy) 
              |> Seq.takeWhile ((<>) 0xFFuy)
    if Seq.isEmpty r then None
    else Some (Seq.skip 1 r)

ただし、適切な障害処理の実装は、関数のセマンティクスによって異なりますgetFrame。たとえば、0xFEが存在し、 が存在しない場合はどうなる0xFFでしょうか? これはデータフレームではないということですか?これは、データ フレームが多くのシーケンスに分割されたことを意味しますか? 等。

于 2013-08-16T13:06:22.890 に答える
1

次の関数はあなたが望むことをすると思います。入力ストリームはガベージとフレームで構成されます。Gargabe は、最初またはフレーム間で発生する可能性があります。ガベージが多すぎるか、フレームが長すぎる場合は、エラーが報告されます。それ以外の場合は、次のフレームが返されます。

let [<Literal>] FrameStart = 0xFE
let [<Literal>] FrameEnd = 0xFF

let [<Literal>] MaxGarbageLength = 5
let [<Literal>] MaxFrameLength = 5

type State<'T> =
| Garbage of int
| Frame of int * 'T list

let getFrame stream =
    let getNextRest stream =
        match Seq.isEmpty stream with
        | true -> None
        | false -> Some(Seq.head stream, Seq.skip 1 stream)

    let rec parse state stream =
        match getNextRest stream with
        | None -> None
        | Some(next, rest) ->
            match state with
            | Garbage n when n >= MaxGarbageLength -> None
            | Garbage n ->
                match next with
                | FrameStart -> parse (Frame(0, [])) rest
                | _ -> parse (Garbage(n+1)) rest
            | Frame(n, _) when n >= MaxFrameLength -> None
            | Frame(n, content) ->
                match next with
                | FrameEnd -> Some(content, rest)
                | _ -> parse (Frame(n+1, content @ [next])) rest

    parse (Garbage 0) stream

ストリームから 2 つのフレームを取得するには:

[<Test>]
let ``can parse two frames with garbage in between``() =
    let stream = Seq.ofList [1;2;3;FrameStart;4;5;6;FrameEnd;7;8;FrameStart;9;0;FrameEnd]

    let (frame1, rest) = (getFrame stream).Value
    frame1 |> should equal [4;5;6]
    rest |> should equal [7;8;FrameStart;9;0;FrameEnd]

    let (frame2, rest) = (getFrame rest).Value
    frame2 |> should equal [9;0]
    rest |> should equal []

エラーは、None を返すことで正しく検出されます (MaxGarbageLength は 5 であるため、以下はエラーを報告することに注意してください)。

[<Test>]
let ``none is returned when there is too much garbage``() =
    let stream = [1;2;3;4;5;6;FrameStart;7;8;9;FrameEnd]
    (getFrame stream).IsNone |> should equal true

これは機能しているようで、簡単に拡張/変更できるはずです。しかし、私にはかなりのコードのように見えます。改善歓迎。

于 2013-08-18T21:54:40.430 に答える