aboutsummaryrefslogtreecommitdiff
path: root/server/src
diff options
context:
space:
mode:
authorGregor Kleen <gkleen@yggdrasil.li>2016-02-14 21:43:23 +0000
committerGregor Kleen <gkleen@yggdrasil.li>2016-02-14 21:43:23 +0000
commit0609858031013f9d95f8104739811d6413331e9b (patch)
treec47d097d2984a088d7793f2f25dcdd6cb592be7b /server/src
parentd4c2170b56b94497e37c94e5e3c9ee6f18a2ed43 (diff)
downloadthermoprint-0609858031013f9d95f8104739811d6413331e9b.tar
thermoprint-0609858031013f9d95f8104739811d6413331e9b.tar.gz
thermoprint-0609858031013f9d95f8104739811d6413331e9b.tar.bz2
thermoprint-0609858031013f9d95f8104739811d6413331e9b.tar.xz
thermoprint-0609858031013f9d95f8104739811d6413331e9b.zip
First work on driver for generic (cheap) printers
Diffstat (limited to 'server/src')
-rw-r--r--server/src/Thermoprint/Server/Printer/Generic.hs100
1 files changed, 100 insertions, 0 deletions
diff --git a/server/src/Thermoprint/Server/Printer/Generic.hs b/server/src/Thermoprint/Server/Printer/Generic.hs
new file mode 100644
index 0000000..bf6ce3b
--- /dev/null
+++ b/server/src/Thermoprint/Server/Printer/Generic.hs
@@ -0,0 +1,100 @@
1{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE ViewPatterns #-}
3{-# LANGUAGE OverloadedStrings #-}
4
5module Thermoprint.Server.Printer.Generic
6 ( genericPrint
7 ) where
8
9import Thermoprint.Printout
10import Thermoprint.API (PrintingError(IOError))
11import Thermoprint.Server.Printer
12
13import System.FileLock
14import System.IO
15
16import Data.Sequence (Seq, (|>), (<|), ViewL(..), viewl)
17import qualified Data.Sequence as Seq
18
19import qualified Data.ByteString.Lazy as Lazy (ByteString)
20import qualified Data.ByteString.Lazy as LBS
21import qualified Data.ByteString.Lazy.Char8 as CLBS
22
23import qualified Data.Text.Lazy as Lazy (Text)
24import qualified Data.Text.Lazy as TL
25
26import Data.Encoding
27import Data.Encoding.CP437
28import Data.Word
29
30import Control.Monad
31import Control.Monad.Reader
32import Control.Monad.Trans.State
33import Control.Monad.IO.Class
34
35import Control.Monad.Trans.Resource
36import Data.Acquire
37
38import Control.Exception.Base (IOException)
39import Control.Monad.Catch
40
41import Data.Foldable
42
43import Data.List (intersperse, genericReplicate, intercalate)
44
45import Data.Int (Int64)
46
47import Prelude hiding (mapM_, sequence_)
48
49lockedFile :: FilePath -> Acquire (FileLock, Handle)
50lockedFile f = mkAcquire ((,) <$> lockFile f Exclusive <*> openFile f AppendMode) (\(lock, h) -> () <$ hClose h <* unlockFile lock)
51
52withLockedFile :: (MonadIO m, MonadMask m) => FilePath -> (Handle -> m a) -> m a
53withLockedFile path f = withEx (lockedFile path) (f . snd)
54
55genericPrint :: FilePath -> PrinterMethod
56genericPrint path = PM $ flip catches handlers . withLockedFile path . print
57 where
58 print printout handle = liftIO $ runReaderT (bracket_ initialize (render printout) finalize) handle >> return Nothing
59 handlers = [ Handler $ return . Just . IOError . (show :: IOException -> String)
60 , Handler $ return . Just . EncError
61 ]
62
63type Render = ReaderT Handle IO ()
64
65encode' :: ByteSink m => String -> m ()
66encode' = encode CP437
67
68width :: Int64
69width = 32
70
71esc :: Word8
72esc = 27
73
74escSequence :: [Word8] -> Render
75escSequence = mapM_ pushWord8 . (esc:)
76
77initialize :: Render
78initialize = replicateM_ 2 $ escSequence [64]
79
80finalize :: Render -- TODO: adjust this to produce proper padding
81finalize = encode' "\n\n\n"
82
83intersperse' :: b -> (a -> b) -> Seq a -> Seq b
84intersperse' _ _ (viewl -> EmptyL) = Seq.empty
85intersperse' _ f (viewl -> x :< (viewl -> EmptyL)) = Seq.singleton $ f x
86intersperse' b f (viewl -> x :< xs) = f x <| b <| intersperse' b f xs
87
88render :: Printout -> Render
89render = sequence_ . intersperse' (encode' "\n\n") renderPar
90
91renderPar :: Paragraph -> Render
92renderPar = mapM_ renderChunk
93 where
94 renderChunk (Raw bs) = mapM_ pushWord8 $ LBS.unpack bs
95 renderChunk (Cooked block) = renderBlock block
96
97renderBlock :: Block -> Render
98renderBlock (VSpace n) = encode' $ genericReplicate n '\n'
99renderBlock (NewlSep xs) = sequence_ intercalate (encode' "\n") . map renderBlock . toList $ xs
100renderBlock (Line x) = undefined